Merge "This code has moved to toybox proper."
diff --git a/adb/client/usb_osx.cpp b/adb/client/usb_osx.cpp
index e4a543b..e366754 100644
--- a/adb/client/usb_osx.cpp
+++ b/adb/client/usb_osx.cpp
@@ -38,6 +38,7 @@
 
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
+#include <android-base/thread_annotations.h>
 
 #include "adb.h"
 #include "transport.h"
@@ -429,7 +430,7 @@
     VLOG(USB) << "RunLoopThread done";
 }
 
-static void usb_cleanup() {
+static void usb_cleanup() NO_THREAD_SAFETY_ANALYSIS {
     VLOG(USB) << "usb_cleanup";
     // Wait until usb operations in RunLoopThread finish, and prevent further operations.
     operate_device_lock.lock();
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index dc6e698..e438801 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -26,8 +26,6 @@
  * SUCH DAMAGE.
  */
 
-#define _LARGEFILE64_SOURCE
-
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
diff --git a/init/README.md b/init/README.md
index 9fc8d47..72b6c6b 100644
--- a/init/README.md
+++ b/init/README.md
@@ -356,9 +356,9 @@
   Init halts executing commands until the forked process exits.
 
 `exec_start <service>`
-> Start service a given service and halt processing of additional init commands
-  until it returns.  It functions similarly to the `exec` command, but uses an
-  existing service definition instead of providing them as arguments.
+> Start a given service and halt the processing of additional init commands
+  until it returns.  The command functions similarly to the `exec` command,
+  but uses an existing service definition in place of the exec argument vector.
 
 `export <name> <value>`
 > Set the environment variable _name_ equal to _value_ in the
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index a2dd677..2b3443f 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -92,6 +92,9 @@
     { 00755, AID_ROOT,         AID_ROOT,         0, 0 },
     // clang-format on
 };
+#ifndef __ANDROID_VNDK__
+auto __for_testing_only__android_dirs = android_dirs;
+#endif
 
 // Rules for files.
 // These rules are applied based on "first match", so they
@@ -238,6 +241,9 @@
     { 00644, AID_ROOT,      AID_ROOT,      0, 0 },
     // clang-format on
 };
+#ifndef __ANDROID_VNDK__
+auto __for_testing_only__android_files = android_files;
+#endif
 
 static size_t strip(const char* path, size_t len, const char suffix[]) {
     if (len < strlen(suffix)) return len;
diff --git a/libcutils/tests/Android.bp b/libcutils/tests/Android.bp
index a0b1d7b..7884190 100644
--- a/libcutils/tests/Android.bp
+++ b/libcutils/tests/Android.bp
@@ -27,7 +27,8 @@
                 "test_str_parms.cpp",
                 "android_get_control_socket_test.cpp",
                 "android_get_control_file_test.cpp",
-                "multiuser_test.cpp"
+                "multiuser_test.cpp",
+                "fs_config.cpp",
             ],
         },
 
diff --git a/libcutils/tests/fs_config.cpp b/libcutils/tests/fs_config.cpp
new file mode 100644
index 0000000..3917a0b
--- /dev/null
+++ b/libcutils/tests/fs_config.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include <android-base/strings.h>
+
+#include <private/android_filesystem_config.h>
+
+extern const struct fs_path_config* __for_testing_only__android_dirs;
+extern const struct fs_path_config* __for_testing_only__android_files;
+
+static void check_one(const struct fs_path_config* paths, const std::string& prefix,
+                      const std::string& alternate) {
+    for (size_t idx = 0; paths[idx].prefix; ++idx) {
+        std::string path(paths[idx].prefix);
+        if (android::base::StartsWith(path, prefix.c_str())) {
+            path = alternate + path.substr(prefix.length());
+            size_t second;
+            for (second = 0; paths[second].prefix; ++second) {
+                if (path == paths[second].prefix) break;
+            }
+            if (!paths[second].prefix) {
+                // guaranteed to fail expectations, trigger test failure with
+                // a message that reports the violation as an inequality.
+                EXPECT_STREQ((prefix + path.substr(alternate.length())).c_str(), path.c_str());
+            }
+        }
+    }
+}
+
+static void check_two(const struct fs_path_config* paths, const std::string& prefix) {
+    ASSERT_FALSE(paths == nullptr);
+    std::string alternate = "system/" + prefix;
+    check_one(paths, prefix, alternate);
+    check_one(paths, alternate, prefix);
+}
+
+TEST(fs_config, vendor_dirs_alias) {
+    check_two(__for_testing_only__android_dirs, "vendor/");
+}
+
+TEST(fs_config, vendor_files_alias) {
+    check_two(__for_testing_only__android_files, "vendor/");
+}
+
+TEST(fs_config, oem_dirs_alias) {
+    check_two(__for_testing_only__android_dirs, "oem/");
+}
+
+TEST(fs_config, oem_files_alias) {
+    check_two(__for_testing_only__android_files, "oem/");
+}
+
+TEST(fs_config, odm_dirs_alias) {
+    check_two(__for_testing_only__android_dirs, "odm/");
+}
+
+TEST(fs_config, odm_files_alias) {
+    check_two(__for_testing_only__android_files, "odm/");
+}
diff --git a/libmemunreachable/.clang-format b/libmemunreachable/.clang-format
new file mode 120000
index 0000000..fd0645f
--- /dev/null
+++ b/libmemunreachable/.clang-format
@@ -0,0 +1 @@
+../.clang-format-2
\ No newline at end of file
diff --git a/libmemunreachable/Android.bp b/libmemunreachable/Android.bp
index 2867f64..cdac76b 100644
--- a/libmemunreachable/Android.bp
+++ b/libmemunreachable/Android.bp
@@ -9,8 +9,16 @@
     clang: true,
     shared_libs: [
         "libbase",
-        "liblog",
     ],
+
+    target: {
+        android: {
+            static_libs: ["libasync_safe"],
+        },
+        host: {
+            shared_libs: ["liblog"],
+        }
+    },
 }
 
 cc_library_shared {
diff --git a/libmemunreachable/HeapWalker.cpp b/libmemunreachable/HeapWalker.cpp
index 62366f2..c365ae5 100644
--- a/libmemunreachable/HeapWalker.cpp
+++ b/libmemunreachable/HeapWalker.cpp
@@ -42,11 +42,9 @@
   } else {
     Range overlap = inserted.first->first;
     if (overlap != range) {
-      ALOGE("range %p-%p overlaps with existing range %p-%p",
-          reinterpret_cast<void*>(begin),
-          reinterpret_cast<void*>(end),
-          reinterpret_cast<void*>(overlap.begin),
-          reinterpret_cast<void*>(overlap.end));
+      MEM_ALOGE("range %p-%p overlaps with existing range %p-%p", reinterpret_cast<void*>(begin),
+                reinterpret_cast<void*>(end), reinterpret_cast<void*>(overlap.begin),
+                reinterpret_cast<void*>(overlap.end));
     }
     return false;
   }
@@ -154,7 +152,7 @@
 
   void* ret = mmap(page, page_size, PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED, -1, 0);
   if (ret == MAP_FAILED) {
-    ALOGE("failed to map page at %p: %s", page, strerror(errno));
+    MEM_ALOGE("failed to map page at %p: %s", page, strerror(errno));
     return false;
   }
 
@@ -167,7 +165,7 @@
     handler.reset();
     return;
   }
-  ALOGW("failed to read page at %p, signal %d", si->si_addr, signal);
+  MEM_ALOGW("failed to read page at %p, signal %d", si->si_addr, signal);
   if (!MapOverPage(si->si_addr)) {
     handler.reset();
   }
diff --git a/libmemunreachable/LeakPipe.cpp b/libmemunreachable/LeakPipe.cpp
index 080f8a7..78117e2 100644
--- a/libmemunreachable/LeakPipe.cpp
+++ b/libmemunreachable/LeakPipe.cpp
@@ -44,11 +44,11 @@
 
   int ret = sendmsg(sock, &hdr, 0);
   if (ret < 0) {
-    ALOGE("failed to send fd: %s", strerror(errno));
+    MEM_ALOGE("failed to send fd: %s", strerror(errno));
     return false;
   }
   if (ret == 0) {
-    ALOGE("eof when sending fd");
+    MEM_ALOGE("eof when sending fd");
     return false;
   }
 
@@ -71,17 +71,17 @@
 
   int ret = recvmsg(sock, &hdr, 0);
   if (ret < 0) {
-    ALOGE("failed to receive fd: %s", strerror(errno));
+    MEM_ALOGE("failed to receive fd: %s", strerror(errno));
     return -1;
   }
   if (ret == 0) {
-    ALOGE("eof when receiving fd");
+    MEM_ALOGE("eof when receiving fd");
     return -1;
   }
 
   struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
   if (cmsg == NULL || cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
-    ALOGE("missing fd while receiving fd");
+    MEM_ALOGE("missing fd while receiving fd");
     return -1;
   }
 
diff --git a/libmemunreachable/LeakPipe.h b/libmemunreachable/LeakPipe.h
index 3f4e0b7..3ea2d8f 100644
--- a/libmemunreachable/LeakPipe.h
+++ b/libmemunreachable/LeakPipe.h
@@ -36,7 +36,7 @@
   LeakPipe() {
     int ret = socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, sv_);
     if (ret < 0) {
-      LOG_ALWAYS_FATAL("failed to create socketpair: %s", strerror(errno));
+      MEM_LOG_ALWAYS_FATAL("failed to create socketpair: %s", strerror(errno));
     }
   }
 
@@ -105,10 +105,10 @@
     bool Send(const T& value) {
       ssize_t ret = TEMP_FAILURE_RETRY(write(fd_, &value, sizeof(T)));
       if (ret < 0) {
-        ALOGE("failed to send value: %s", strerror(errno));
+        MEM_ALOGE("failed to send value: %s", strerror(errno));
         return false;
       } else if (static_cast<size_t>(ret) != sizeof(T)) {
-        ALOGE("eof while writing value");
+        MEM_ALOGE("eof while writing value");
         return false;
       }
 
@@ -124,10 +124,10 @@
 
       ssize_t ret = TEMP_FAILURE_RETRY(write(fd_, vector.data(), size));
       if (ret < 0) {
-        ALOGE("failed to send vector: %s", strerror(errno));
+        MEM_ALOGE("failed to send vector: %s", strerror(errno));
         return false;
       } else if (static_cast<size_t>(ret) != size) {
-        ALOGE("eof while writing vector");
+        MEM_ALOGE("eof while writing vector");
         return false;
       }
 
@@ -143,10 +143,10 @@
     bool Receive(T* value) {
       ssize_t ret = TEMP_FAILURE_RETRY(read(fd_, reinterpret_cast<void*>(value), sizeof(T)));
       if (ret < 0) {
-        ALOGE("failed to receive value: %s", strerror(errno));
+        MEM_ALOGE("failed to receive value: %s", strerror(errno));
         return false;
       } else if (static_cast<size_t>(ret) != sizeof(T)) {
-        ALOGE("eof while receiving value");
+        MEM_ALOGE("eof while receiving value");
         return false;
       }
 
@@ -166,10 +166,10 @@
       while (size > 0) {
         ssize_t ret = TEMP_FAILURE_RETRY(read(fd_, ptr, size));
         if (ret < 0) {
-          ALOGE("failed to send vector: %s", strerror(errno));
+          MEM_ALOGE("failed to send vector: %s", strerror(errno));
           return false;
         } else if (ret == 0) {
-          ALOGE("eof while reading vector");
+          MEM_ALOGE("eof while reading vector");
           return false;
         }
         size -= ret;
diff --git a/libmemunreachable/MemUnreachable.cpp b/libmemunreachable/MemUnreachable.cpp
index ac19a66..e7c0beb 100644
--- a/libmemunreachable/MemUnreachable.cpp
+++ b/libmemunreachable/MemUnreachable.cpp
@@ -78,51 +78,49 @@
 
 bool MemUnreachable::CollectAllocations(const allocator::vector<ThreadInfo>& threads,
     const allocator::vector<Mapping>& mappings) {
-  ALOGI("searching process %d for allocations", pid_);
+  MEM_ALOGI("searching process %d for allocations", pid_);
   allocator::vector<Mapping> heap_mappings{mappings};
   allocator::vector<Mapping> anon_mappings{mappings};
   allocator::vector<Mapping> globals_mappings{mappings};
   allocator::vector<Mapping> stack_mappings{mappings};
-  if (!ClassifyMappings(mappings, heap_mappings, anon_mappings,
-      globals_mappings, stack_mappings)) {
+  if (!ClassifyMappings(mappings, heap_mappings, anon_mappings, globals_mappings, stack_mappings)) {
     return false;
   }
 
   for (auto it = heap_mappings.begin(); it != heap_mappings.end(); it++) {
-    ALOGV("Heap mapping %" PRIxPTR "-%" PRIxPTR " %s", it->begin, it->end, it->name);
-    HeapIterate(*it, [&](uintptr_t base, size_t size) {
-      heap_walker_.Allocation(base, base + size);
-    });
+    MEM_ALOGV("Heap mapping %" PRIxPTR "-%" PRIxPTR " %s", it->begin, it->end, it->name);
+    HeapIterate(*it,
+                [&](uintptr_t base, size_t size) { heap_walker_.Allocation(base, base + size); });
   }
 
   for (auto it = anon_mappings.begin(); it != anon_mappings.end(); it++) {
-    ALOGV("Anon mapping %" PRIxPTR "-%" PRIxPTR " %s", it->begin, it->end, it->name);
+    MEM_ALOGV("Anon mapping %" PRIxPTR "-%" PRIxPTR " %s", it->begin, it->end, it->name);
     heap_walker_.Allocation(it->begin, it->end);
   }
 
   for (auto it = globals_mappings.begin(); it != globals_mappings.end(); it++) {
-    ALOGV("Globals mapping %" PRIxPTR "-%" PRIxPTR " %s", it->begin, it->end, it->name);
+    MEM_ALOGV("Globals mapping %" PRIxPTR "-%" PRIxPTR " %s", it->begin, it->end, it->name);
     heap_walker_.Root(it->begin, it->end);
   }
 
   for (auto thread_it = threads.begin(); thread_it != threads.end(); thread_it++) {
     for (auto it = stack_mappings.begin(); it != stack_mappings.end(); it++) {
       if (thread_it->stack.first >= it->begin && thread_it->stack.first <= it->end) {
-        ALOGV("Stack %" PRIxPTR "-%" PRIxPTR " %s", thread_it->stack.first, it->end, it->name);
+        MEM_ALOGV("Stack %" PRIxPTR "-%" PRIxPTR " %s", thread_it->stack.first, it->end, it->name);
         heap_walker_.Root(thread_it->stack.first, it->end);
       }
     }
     heap_walker_.Root(thread_it->regs);
   }
 
-  ALOGI("searching done");
+  MEM_ALOGI("searching done");
 
   return true;
 }
 
 bool MemUnreachable::GetUnreachableMemory(allocator::vector<Leak>& leaks,
     size_t limit, size_t* num_leaks, size_t* leak_bytes) {
-  ALOGI("sweeping process %d for unreachable memory", pid_);
+  MEM_ALOGI("sweeping process %d for unreachable memory", pid_);
   leaks.clear();
 
   if (!heap_walker_.DetectLeaks()) {
@@ -133,9 +131,9 @@
   allocator::vector<Range> leaked1{allocator_};
   heap_walker_.Leaked(leaked1, 0, num_leaks, leak_bytes);
 
-  ALOGI("sweeping done");
+  MEM_ALOGI("sweeping done");
 
-  ALOGI("folding related leaks");
+  MEM_ALOGI("folding related leaks");
 
   LeakFolding folding(allocator_, heap_walker_);
   if (!folding.FoldLeaks()) {
@@ -188,7 +186,7 @@
         std::min(leak->size, Leak::contents_length));
   }
 
-  ALOGI("folding done");
+  MEM_ALOGI("folding done");
 
   std::sort(leaks.begin(), leaks.end(), [](const Leak& a, const Leak& b) {
     return a.total_size > b.total_size;
@@ -276,7 +274,7 @@
     /////////////////////////////////////////////
     // Collection thread
     /////////////////////////////////////////////
-    ALOGI("collecting thread info for process %d...", parent_pid);
+    MEM_ALOGI("collecting thread info for process %d...", parent_pid);
 
     ThreadCapture thread_capture(parent_pid, heap);
     allocator::vector<ThreadInfo> thread_info(heap);
@@ -351,7 +349,7 @@
     } else {
       // Nothing left to do in the collection thread, return immediately,
       // releasing all the captured threads.
-      ALOGI("collection thread done");
+      MEM_ALOGI("collection thread done");
       return 0;
     }
   }};
@@ -397,10 +395,10 @@
     return false;
   }
 
-  ALOGI("unreachable memory detection done");
-  ALOGE("%zu bytes in %zu allocation%s unreachable out of %zu bytes in %zu allocation%s",
-      info.leak_bytes, info.num_leaks, plural(info.num_leaks),
-      info.allocation_bytes, info.num_allocations, plural(info.num_allocations));
+  MEM_ALOGI("unreachable memory detection done");
+  MEM_ALOGE("%zu bytes in %zu allocation%s unreachable out of %zu bytes in %zu allocation%s",
+            info.leak_bytes, info.num_leaks, plural(info.num_leaks), info.allocation_bytes,
+            info.num_allocations, plural(info.num_allocations));
   return true;
 }
 
@@ -517,7 +515,7 @@
   }
 
   for (auto it = info.leaks.begin(); it != info.leaks.end(); it++) {
-    ALOGE("%s", it->ToString(log_contents).c_str());
+    MEM_ALOGE("%s", it->ToString(log_contents).c_str());
   }
   return true;
 }
diff --git a/libmemunreachable/PtracerThread.cpp b/libmemunreachable/PtracerThread.cpp
index 4e3c41e..73b0493 100644
--- a/libmemunreachable/PtracerThread.cpp
+++ b/libmemunreachable/PtracerThread.cpp
@@ -70,7 +70,7 @@
     child_pid_(0) {
   stack_ = std::make_unique<Stack>(PTHREAD_STACK_MIN);
   if (stack_->top() == nullptr) {
-    LOG_ALWAYS_FATAL("failed to mmap child stack: %s", strerror(errno));
+    MEM_LOG_ALWAYS_FATAL("failed to mmap child stack: %s", strerror(errno));
   }
 
   func_ = std::function<int()>{[&, func]() -> int {
@@ -102,7 +102,7 @@
        CLONE_VM|CLONE_FS|CLONE_FILES/*|CLONE_UNTRACED*/,
        reinterpret_cast<void*>(&func_));
   if (child_pid_ < 0) {
-    ALOGE("failed to clone child: %s", strerror(errno));
+    MEM_ALOGE("failed to clone child: %s", strerror(errno));
     return false;
   }
 
@@ -120,7 +120,7 @@
   int status;
   int ret = TEMP_FAILURE_RETRY(waitpid(child_pid_, &status, __WALL));
   if (ret < 0) {
-    ALOGE("waitpid %d failed: %s", child_pid_, strerror(errno));
+    MEM_ALOGE("waitpid %d failed: %s", child_pid_, strerror(errno));
     return -1;
   }
 
@@ -131,7 +131,7 @@
   } else if (WIFSIGNALED(status)) {
     return -WTERMSIG(status);
   } else {
-    ALOGE("unexpected status %x", status);
+    MEM_ALOGE("unexpected status %x", status);
     return -1;
   }
 }
diff --git a/libmemunreachable/ScopedPipe.h b/libmemunreachable/ScopedPipe.h
index 9beef9a..7f44953 100644
--- a/libmemunreachable/ScopedPipe.h
+++ b/libmemunreachable/ScopedPipe.h
@@ -26,7 +26,7 @@
   ScopedPipe() : pipefd_{-1, -1} {
     int ret = pipe2(pipefd_, O_CLOEXEC);
     if (ret < 0) {
-      LOG_ALWAYS_FATAL("failed to open pipe");
+      MEM_LOG_ALWAYS_FATAL("failed to open pipe");
     }
   }
   ~ScopedPipe() {
diff --git a/libmemunreachable/ScopedSignalHandler.h b/libmemunreachable/ScopedSignalHandler.h
index 1fd9d4d..ada2ae4 100644
--- a/libmemunreachable/ScopedSignalHandler.h
+++ b/libmemunreachable/ScopedSignalHandler.h
@@ -37,22 +37,18 @@
 
   template <class F>
   void install(int signal, F&& f) {
-    LOG_ALWAYS_FATAL_IF(signal_ != -1, "ScopedSignalHandler already installed");
+    MEM_LOG_ALWAYS_FATAL_IF(signal_ != -1, "ScopedSignalHandler already installed");
 
     handler_ = SignalFn(std::allocator_arg, allocator_,
-        [=](int signal, siginfo_t* si, void* uctx) {
-          f(*this, signal, si, uctx);
-        });
+                        [=](int signal, siginfo_t* si, void* uctx) { f(*this, signal, si, uctx); });
 
-    struct sigaction act{};
-    act.sa_sigaction = [](int signal, siginfo_t* si, void* uctx) {
-      handler_(signal, si, uctx);
-    };
+    struct sigaction act {};
+    act.sa_sigaction = [](int signal, siginfo_t* si, void* uctx) { handler_(signal, si, uctx); };
     act.sa_flags = SA_SIGINFO;
 
     int ret = sigaction(signal, &act, &old_act_);
     if (ret < 0) {
-      LOG_ALWAYS_FATAL("failed to install segfault handler: %s", strerror(errno));
+      MEM_LOG_ALWAYS_FATAL("failed to install segfault handler: %s", strerror(errno));
     }
 
     signal_ = signal;
@@ -62,7 +58,7 @@
     if (signal_ != -1) {
       int ret = sigaction(signal_, &old_act_, NULL);
       if (ret < 0) {
-        ALOGE("failed to uninstall segfault handler");
+        MEM_ALOGE("failed to uninstall segfault handler");
       }
       handler_ = SignalFn{};
       signal_ = -1;
diff --git a/libmemunreachable/ThreadCapture.cpp b/libmemunreachable/ThreadCapture.cpp
index 9155c29..3891f2d 100644
--- a/libmemunreachable/ThreadCapture.cpp
+++ b/libmemunreachable/ThreadCapture.cpp
@@ -110,7 +110,7 @@
 
   android::base::unique_fd fd(open(path, O_CLOEXEC | O_DIRECTORY | O_RDONLY));
   if (fd == -1) {
-    ALOGE("failed to open %s: %s", path, strerror(errno));
+    MEM_ALOGE("failed to open %s: %s", path, strerror(errno));
     return false;
   }
 
@@ -126,7 +126,7 @@
   do {
     nread = syscall(SYS_getdents64, fd.get(), dirent_buf, sizeof(dirent_buf));
     if (nread < 0) {
-      ALOGE("failed to get directory entries from %s: %s", path, strerror(errno));
+      MEM_ALOGE("failed to get directory entries from %s: %s", path, strerror(errno));
       return false;
     } else if (nread > 0) {
       ssize_t off = 0;
@@ -177,8 +177,7 @@
 void ThreadCaptureImpl::PtraceDetach(pid_t tid, unsigned int signal) {
   void* sig_ptr = reinterpret_cast<void*>(static_cast<uintptr_t>(signal));
   if (ptrace(PTRACE_DETACH, tid, NULL, sig_ptr) < 0 && errno != ESRCH) {
-    ALOGE("failed to detach from thread %d of process %d: %s", tid, pid_,
-        strerror(errno));
+    MEM_ALOGE("failed to detach from thread %d of process %d: %s", tid, pid_, strerror(errno));
   }
 }
 
@@ -187,8 +186,7 @@
 int ThreadCaptureImpl::PtraceAttach(pid_t tid) {
   int ret = ptrace(PTRACE_SEIZE, tid, NULL, NULL);
   if (ret < 0) {
-    ALOGE("failed to attach to thread %d of process %d: %s", tid, pid_,
-        strerror(errno));
+    MEM_ALOGE("failed to attach to thread %d of process %d: %s", tid, pid_, strerror(errno));
     return -1;
   }
 
@@ -200,8 +198,7 @@
     if (errno == ESRCH) {
       return 0;
     } else {
-      ALOGE("failed to interrupt thread %d of process %d: %s", tid, pid_,
-          strerror(errno));
+      MEM_ALOGE("failed to interrupt thread %d of process %d: %s", tid, pid_, strerror(errno));
       PtraceDetach(tid, 0);
       return -1;
     }
@@ -219,8 +216,7 @@
   iovec.iov_len = sizeof(regs);
 
   if (ptrace(PTRACE_GETREGSET, tid, reinterpret_cast<void*>(NT_PRSTATUS), &iovec)) {
-    ALOGE("ptrace getregset for thread %d of process %d failed: %s",
-        tid, pid_, strerror(errno));
+    MEM_ALOGE("ptrace getregset for thread %d of process %d failed: %s", tid, pid_, strerror(errno));
     return false;
   }
 
@@ -258,15 +254,13 @@
 
   int status = 0;
   if (TEMP_FAILURE_RETRY(waitpid(tid, &status, __WALL)) < 0) {
-    ALOGE("failed to wait for pause of thread %d of process %d: %s", tid, pid_,
-        strerror(errno));
+    MEM_ALOGE("failed to wait for pause of thread %d of process %d: %s", tid, pid_, strerror(errno));
     PtraceDetach(tid, 0);
     return -1;
   }
 
   if (!WIFSTOPPED(status)) {
-    ALOGE("thread %d of process %d was not paused after waitpid, killed?",
-        tid, pid_);
+    MEM_ALOGE("thread %d of process %d was not paused after waitpid, killed?", tid, pid_);
     return 0;
   }
 
@@ -285,8 +279,8 @@
         // normal ptrace interrupt stop
         break;
       default:
-        ALOGE("unexpected signal %d with PTRACE_EVENT_STOP for thread %d of process %d",
-            signal, tid, pid_);
+        MEM_ALOGE("unexpected signal %d with PTRACE_EVENT_STOP for thread %d of process %d", signal,
+                  tid, pid_);
         return -1;
     }
   } else {
diff --git a/libmemunreachable/log.h b/libmemunreachable/log.h
index cdfbfd9..1725c53 100644
--- a/libmemunreachable/log.h
+++ b/libmemunreachable/log.h
@@ -19,6 +19,32 @@
 
 #define LOG_TAG "libmemunreachable"
 
+#if defined(__ANDROID__)
+
+#include <async_safe/log.h>
+
+#define MEM_ALOGE(...) async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, ##__VA_ARGS__)
+#define MEM_ALOGW(...) async_safe_format_log(ANDROID_LOG_WARN, LOG_TAG, ##__VA_ARGS__)
+#define MEM_ALOGI(...) async_safe_format_log(ANDROID_LOG_INFO, LOG_TAG, ##__VA_ARGS__)
+#define MEM_ALOGV(...) async_safe_format_log(ANDROID_LOG_VERBOSE, LOG_TAG, ##__VA_ARGS__)
+
+#define MEM_LOG_ALWAYS_FATAL(...) async_safe_fatal(__VA_ARGS__)
+
+#define MEM_LOG_ALWAYS_FATAL_IF(cond, ...) \
+  ((__predict_false(cond)) ? async_safe_fatal(__VA_ARGS__) : (void)0)
+
+#else
+
 #include <log/log.h>
 
+#define MEM_ALOGW ALOGW
+#define MEM_ALOGE ALOGE
+#define MEM_ALOGV ALOGV
+#define MEM_ALOGI ALOGI
+
+#define MEM_LOG_ALWAYS_FATAL LOG_ALWAYS_FATAL
+#define MEM_LOG_ALWAYS_FATAL_IF LOG_ALWAYS_FATAL_IF
+
+#endif
+
 #endif // LIBMEMUNREACHABLE_LOG_H_