Merge "emulator: Use distinct serial names for simultaneous qemu pipes."
diff --git a/debuggerd/backtrace.cpp b/debuggerd/backtrace.cpp
index b6916e5..32843d8 100644
--- a/debuggerd/backtrace.cpp
+++ b/debuggerd/backtrace.cpp
@@ -91,7 +91,8 @@
   if (backtrace->Unwind(0)) {
     dump_backtrace_to_log(backtrace.get(), log, "  ");
   } else {
-    ALOGE("Unwind failed: tid = %d", tid);
+    ALOGE("Unwind failed: tid = %d: %s", tid,
+          backtrace->GetErrorString(backtrace->GetError()).c_str());
   }
 }
 
diff --git a/include/backtrace/Backtrace.h b/include/backtrace/Backtrace.h
index f440bd2..c896ab8 100644
--- a/include/backtrace/Backtrace.h
+++ b/include/backtrace/Backtrace.h
@@ -34,6 +34,24 @@
 typedef uint32_t word_t;
 #endif
 
+enum BacktraceUnwindError : uint32_t {
+  BACKTRACE_UNWIND_NO_ERROR,
+  // Something failed while trying to perform the setup to begin the unwind.
+  BACKTRACE_UNWIND_ERROR_SETUP_FAILED,
+  // There is no map information to use with the unwind.
+  BACKTRACE_UNWIND_ERROR_MAP_MISSING,
+  // An error occurred that indicates a programming error.
+  BACKTRACE_UNWIND_ERROR_INTERNAL,
+  // The thread to unwind has disappeared before the unwind can begin.
+  BACKTRACE_UNWIND_ERROR_THREAD_DOESNT_EXIST,
+  // The thread to unwind has not responded to a signal in a timely manner.
+  BACKTRACE_UNWIND_ERROR_THREAD_TIMEOUT,
+  // Attempt to do an unsupported operation.
+  BACKTRACE_UNWIND_ERROR_UNSUPPORTED_OPERATION,
+  // Attempt to do an offline unwind without a context.
+  BACKTRACE_UNWIND_ERROR_NO_CONTEXT,
+};
+
 struct backtrace_frame_data_t {
   size_t num;             // The current fame number.
   uintptr_t pc;           // The absolute pc.
@@ -127,6 +145,10 @@
 
   BacktraceMap* GetMap() { return map_; }
 
+  BacktraceUnwindError GetError() { return error_; }
+
+  std::string GetErrorString(BacktraceUnwindError error);
+
 protected:
   Backtrace(pid_t pid, pid_t tid, BacktraceMap* map);
 
@@ -145,6 +167,8 @@
   bool map_shared_;
 
   std::vector<backtrace_frame_data_t> frames_;
+
+  BacktraceUnwindError error_;
 };
 
 #endif // _BACKTRACE_BACKTRACE_H
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index baa3d0f..995abc0 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -148,3 +148,24 @@
     return new UnwindPtrace(pid, tid, map);
   }
 }
+
+std::string Backtrace::GetErrorString(BacktraceUnwindError error) {
+  switch (error) {
+  case BACKTRACE_UNWIND_NO_ERROR:
+    return "No error";
+  case BACKTRACE_UNWIND_ERROR_SETUP_FAILED:
+    return "Setup failed";
+  case BACKTRACE_UNWIND_ERROR_MAP_MISSING:
+    return "No map found";
+  case BACKTRACE_UNWIND_ERROR_INTERNAL:
+    return "Internal libbacktrace error, please submit a bugreport";
+  case BACKTRACE_UNWIND_ERROR_THREAD_DOESNT_EXIST:
+    return "Thread doesn't exist";
+  case BACKTRACE_UNWIND_ERROR_THREAD_TIMEOUT:
+    return "Thread has not repsonded to signal in time";
+  case BACKTRACE_UNWIND_ERROR_UNSUPPORTED_OPERATION:
+    return "Attempt to use an unsupported feature";
+  case BACKTRACE_UNWIND_ERROR_NO_CONTEXT:
+    return "Attempt to do an offline unwind without a context";
+  }
+}
diff --git a/libbacktrace/BacktraceCurrent.cpp b/libbacktrace/BacktraceCurrent.cpp
index 8e22366..5173e2c 100644
--- a/libbacktrace/BacktraceCurrent.cpp
+++ b/libbacktrace/BacktraceCurrent.cpp
@@ -24,6 +24,8 @@
 #include <ucontext.h>
 #include <unistd.h>
 
+#include <stdlib.h>
+
 #include <string>
 
 #include <backtrace/Backtrace.h>
@@ -65,9 +67,11 @@
 bool BacktraceCurrent::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
   if (GetMap() == nullptr) {
     // Without a map object, we can't do anything.
+    error_ = BACKTRACE_UNWIND_ERROR_MAP_MISSING;
     return false;
   }
 
+  error_ = BACKTRACE_UNWIND_NO_ERROR;
   if (ucontext) {
     return UnwindFromContext(num_ignore_frames, ucontext);
   }
@@ -138,11 +142,19 @@
     BACK_LOGE("sigaction failed: %s", strerror(errno));
     ThreadEntry::Remove(entry);
     pthread_mutex_unlock(&g_sigaction_mutex);
+    error_ = BACKTRACE_UNWIND_ERROR_INTERNAL;
     return false;
   }
 
   if (tgkill(Pid(), Tid(), THREAD_SIGNAL) != 0) {
-    BACK_LOGE("tgkill %d failed: %s", Tid(), strerror(errno));
+    // Do not emit an error message, this might be expected. Set the
+    // error and let the caller decide.
+    if (errno == ESRCH) {
+      error_ = BACKTRACE_UNWIND_ERROR_THREAD_DOESNT_EXIST;
+    } else {
+      error_ = BACKTRACE_UNWIND_ERROR_INTERNAL;
+    }
+
     sigaction(THREAD_SIGNAL, &oldact, nullptr);
     ThreadEntry::Remove(entry);
     pthread_mutex_unlock(&g_sigaction_mutex);
@@ -183,7 +195,13 @@
       BACK_LOGW("Timed out waiting for signal handler to indicate it finished.");
     }
   } else {
-    BACK_LOGE("Timed out waiting for signal handler to get ucontext data.");
+    // Check to see if the thread has disappeared.
+    if (tgkill(Pid(), Tid(), 0) == -1 && errno == ESRCH) {
+      error_ = BACKTRACE_UNWIND_ERROR_THREAD_DOESNT_EXIST;
+    } else {
+      error_ = BACKTRACE_UNWIND_ERROR_THREAD_TIMEOUT;
+      BACK_LOGE("Timed out waiting for signal handler to get ucontext data.");
+    }
   }
 
   ThreadEntry::Remove(entry);
diff --git a/libbacktrace/BacktraceOffline.cpp b/libbacktrace/BacktraceOffline.cpp
index e84ae74..ac14046 100644
--- a/libbacktrace/BacktraceOffline.cpp
+++ b/libbacktrace/BacktraceOffline.cpp
@@ -129,9 +129,11 @@
 bool BacktraceOffline::Unwind(size_t num_ignore_frames, ucontext_t* context) {
   if (context == nullptr) {
     BACK_LOGW("The context is needed for offline backtracing.");
+    error_ = BACKTRACE_UNWIND_ERROR_NO_CONTEXT;
     return false;
   }
   context_ = context;
+  error_ = BACKTRACE_UNWIND_NO_ERROR;
 
   unw_addr_space_t addr_space = unw_create_addr_space(&accessors, 0);
   unw_cursor_t cursor;
@@ -139,6 +141,7 @@
   if (ret != 0) {
     BACK_LOGW("unw_init_remote failed %d", ret);
     unw_destroy_addr_space(addr_space);
+    error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
     return false;
   }
   size_t num_frames = 0;
diff --git a/libbacktrace/UnwindCurrent.cpp b/libbacktrace/UnwindCurrent.cpp
index 67e583f..666c481 100644
--- a/libbacktrace/UnwindCurrent.cpp
+++ b/libbacktrace/UnwindCurrent.cpp
@@ -70,6 +70,7 @@
     int ret = unw_getcontext(&context_);
     if (ret < 0) {
       BACK_LOGW("unw_getcontext failed %d", ret);
+      error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
       return false;
     }
   } else {
@@ -81,6 +82,7 @@
   int ret = unw_init_local(cursor.get(), &context_);
   if (ret < 0) {
     BACK_LOGW("unw_init_local failed %d", ret);
+    error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
     return false;
   }
 
diff --git a/libbacktrace/UnwindPtrace.cpp b/libbacktrace/UnwindPtrace.cpp
index 07c2430..306d2ac 100644
--- a/libbacktrace/UnwindPtrace.cpp
+++ b/libbacktrace/UnwindPtrace.cpp
@@ -50,17 +50,22 @@
 bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
   if (GetMap() == nullptr) {
     // Without a map object, we can't do anything.
+    error_ = BACKTRACE_UNWIND_ERROR_MAP_MISSING;
     return false;
   }
 
+  error_ = BACKTRACE_UNWIND_NO_ERROR;
+
   if (ucontext) {
     BACK_LOGW("Unwinding from a specified context not supported yet.");
+    error_ = BACKTRACE_UNWIND_ERROR_UNSUPPORTED_OPERATION;
     return false;
   }
 
   addr_space_ = unw_create_addr_space(&_UPT_accessors, 0);
   if (!addr_space_) {
     BACK_LOGW("unw_create_addr_space failed.");
+    error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
     return false;
   }
 
@@ -70,6 +75,7 @@
   upt_info_ = reinterpret_cast<struct UPT_info*>(_UPT_create(Tid()));
   if (!upt_info_) {
     BACK_LOGW("Failed to create upt info.");
+    error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
     return false;
   }
 
@@ -77,6 +83,7 @@
   int ret = unw_init_remote(&cursor, addr_space_, upt_info_);
   if (ret < 0) {
     BACK_LOGW("unw_init_remote failed %d", ret);
+    error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
     return false;
   }
 
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index ab09564..df6c6c1 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -162,6 +162,7 @@
       Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
   ASSERT_TRUE(backtrace.get() != nullptr);
   ASSERT_TRUE(backtrace->Unwind(0));
+  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError());
 
   VerifyLevelDump(backtrace.get());
 }
@@ -183,6 +184,7 @@
       Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
   ASSERT_TRUE(backtrace.get() != nullptr);
   ASSERT_TRUE(backtrace->Unwind(0));
+  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError());
 
   VerifyMaxDump(backtrace.get());
 }
@@ -200,6 +202,7 @@
   std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), tid));
   ASSERT_TRUE(backtrace.get() != nullptr);
   ASSERT_TRUE(backtrace->Unwind(0));
+  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError());
 
   VerifyFunc(backtrace.get());
 }
@@ -220,6 +223,7 @@
   std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), getpid()));
   ASSERT_TRUE(backtrace.get() != nullptr);
   ASSERT_TRUE(backtrace->Unwind(0));
+  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError());
 
   ASSERT_TRUE(backtrace->NumFrames() != 0);
   for (const auto& frame : *backtrace ) {
@@ -267,16 +271,19 @@
       Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
   ASSERT_TRUE(all.get() != nullptr);
   ASSERT_TRUE(all->Unwind(0));
+  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, all->GetError());
 
   std::unique_ptr<Backtrace> ign1(
       Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
   ASSERT_TRUE(ign1.get() != nullptr);
   ASSERT_TRUE(ign1->Unwind(1));
+  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign1->GetError());
 
   std::unique_ptr<Backtrace> ign2(
       Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
   ASSERT_TRUE(ign2.get() != nullptr);
   ASSERT_TRUE(ign2->Unwind(2));
+  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign2->GetError());
 
   VerifyIgnoreFrames(all.get(), ign1.get(), ign2.get(), "VerifyLevelIgnoreFrames");
 }
@@ -314,6 +321,7 @@
       std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get()));
       ASSERT_TRUE(backtrace.get() != nullptr);
       ASSERT_TRUE(backtrace->Unwind(0));
+      ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError());
       if (ReadyFunc(backtrace.get())) {
         VerifyFunc(backtrace.get());
         verified = true;
@@ -372,10 +380,12 @@
   std::unique_ptr<Backtrace> ign1(Backtrace::Create(bt_all->Pid(), BACKTRACE_CURRENT_THREAD));
   ASSERT_TRUE(ign1.get() != nullptr);
   ASSERT_TRUE(ign1->Unwind(1));
+  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign1->GetError());
 
   std::unique_ptr<Backtrace> ign2(Backtrace::Create(bt_all->Pid(), BACKTRACE_CURRENT_THREAD));
   ASSERT_TRUE(ign2.get() != nullptr);
   ASSERT_TRUE(ign2->Unwind(2));
+  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign2->GetError());
 
   VerifyIgnoreFrames(bt_all, ign1.get(), ign2.get(), nullptr);
 }
@@ -462,6 +472,7 @@
   std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), gettid()));
   ASSERT_TRUE(backtrace.get() != nullptr);
   ASSERT_TRUE(backtrace->Unwind(0));
+  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError());
 
   VerifyLevelDump(backtrace.get());
 }
@@ -474,6 +485,7 @@
   std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), gettid()));
   ASSERT_TRUE(backtrace.get() != nullptr);
   ASSERT_TRUE(backtrace->Unwind(0));
+  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError());
 
   VerifyMaxDump(backtrace.get());
 }
@@ -515,6 +527,7 @@
   std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid));
   ASSERT_TRUE(backtrace.get() != nullptr);
   ASSERT_TRUE(backtrace->Unwind(0));
+  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError());
 
   VerifyLevelDump(backtrace.get());
 
@@ -554,14 +567,17 @@
   std::unique_ptr<Backtrace> all(Backtrace::Create(getpid(), thread_data.tid));
   ASSERT_TRUE(all.get() != nullptr);
   ASSERT_TRUE(all->Unwind(0));
+  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, all->GetError());
 
   std::unique_ptr<Backtrace> ign1(Backtrace::Create(getpid(), thread_data.tid));
   ASSERT_TRUE(ign1.get() != nullptr);
   ASSERT_TRUE(ign1->Unwind(1));
+  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign1->GetError());
 
   std::unique_ptr<Backtrace> ign2(Backtrace::Create(getpid(), thread_data.tid));
   ASSERT_TRUE(ign2.get() != nullptr);
   ASSERT_TRUE(ign2->Unwind(2));
+  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign2->GetError());
 
   VerifyIgnoreFrames(all.get(), ign1.get(), ign2.get(), nullptr);
 
@@ -592,6 +608,7 @@
   std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid));
   ASSERT_TRUE(backtrace.get() != nullptr);
   ASSERT_TRUE(backtrace->Unwind(0));
+  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError());
 
   VerifyMaxDump(backtrace.get());
 
@@ -718,18 +735,21 @@
   Backtrace* back1 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map1);
   ASSERT_TRUE(back1 != nullptr);
   EXPECT_TRUE(back1->Unwind(0));
+  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, back1->GetError());
   delete back1;
   delete map1;
 
   Backtrace* back2 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map2);
   ASSERT_TRUE(back2 != nullptr);
   EXPECT_TRUE(back2->Unwind(0));
+  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, back2->GetError());
   delete back2;
   delete map2;
 
   Backtrace* back3 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map3);
   ASSERT_TRUE(back3 != nullptr);
   EXPECT_TRUE(back3->Unwind(0));
+  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, back3->GetError());
   delete back3;
   delete map3;
 }
@@ -1308,6 +1328,7 @@
                                                          BACKTRACE_CURRENT_THREAD));
   ASSERT_TRUE(backtrace.get() != nullptr);
   ASSERT_TRUE(backtrace->Unwind(0));
+  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError());
 
   size_t frame_num;
   ASSERT_TRUE(FindFuncFrameInBacktrace(backtrace.get(), test_func, &frame_num));
@@ -1364,6 +1385,7 @@
     std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, BACKTRACE_CURRENT_THREAD));
     ASSERT_TRUE(backtrace.get() != nullptr);
     ASSERT_TRUE(backtrace->Unwind(0));
+    ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError());
 
     size_t frame_num;
     if (FindFuncFrameInBacktrace(backtrace.get(),
@@ -1387,6 +1409,14 @@
   ASSERT_TRUE(done) << "Test function never found in unwind.";
 }
 
+TEST(libbacktrace, unwind_thread_doesnt_exist) {
+  std::unique_ptr<Backtrace> backtrace(
+      Backtrace::Create(BACKTRACE_CURRENT_PROCESS, 99999999));
+  ASSERT_TRUE(backtrace.get() != nullptr);
+  ASSERT_FALSE(backtrace->Unwind(0));
+  ASSERT_EQ(BACKTRACE_UNWIND_ERROR_THREAD_DOESNT_EXIST, backtrace->GetError());
+}
+
 #if defined(ENABLE_PSS_TESTS)
 #include "GetPss.h"
 
@@ -1398,6 +1428,7 @@
     Backtrace* backtrace = Backtrace::Create(pid, tid);
     ASSERT_TRUE(backtrace != nullptr);
     ASSERT_TRUE(backtrace->Unwind(0));
+    ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError());
     delete backtrace;
   }
   size_t stable_pss = GetPssBytes();
@@ -1408,6 +1439,7 @@
     Backtrace* backtrace = Backtrace::Create(pid, tid);
     ASSERT_TRUE(backtrace != nullptr);
     ASSERT_TRUE(backtrace->Unwind(0));
+    ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError());
     delete backtrace;
   }
   size_t new_pss = GetPssBytes();
diff --git a/liblog/Android.mk b/liblog/Android.mk
index dd5b518..6d53a4a 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -39,7 +39,7 @@
 LOCAL_SRC_FILES_darwin := event_tag_map.c
 LOCAL_SRC_FILES_linux := event_tag_map.c
 LOCAL_SRC_FILES_windows := uio.c
-LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1 -Werror $(liblog_cflags)
+LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1 -Werror -fvisibility=hidden $(liblog_cflags)
 LOCAL_MULTILIB := both
 LOCAL_MODULE_HOST_OS := darwin linux windows
 include $(BUILD_HOST_STATIC_LIBRARY)
@@ -59,7 +59,7 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := liblog
 LOCAL_SRC_FILES := $(liblog_target_sources)
-LOCAL_CFLAGS := -Werror $(liblog_cflags)
+LOCAL_CFLAGS := -Werror -fvisibility=hidden $(liblog_cflags)
 # AddressSanitizer runtime library depends on liblog.
 LOCAL_SANITIZE := never
 include $(BUILD_STATIC_LIBRARY)
@@ -67,7 +67,7 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := liblog
 LOCAL_WHOLE_STATIC_LIBRARIES := liblog
-LOCAL_CFLAGS := -Werror $(liblog_cflags)
+LOCAL_CFLAGS := -Werror -fvisibility=hidden $(liblog_cflags)
 
 # TODO: This is to work around b/24465209. Remove after root cause is fixed
 LOCAL_LDFLAGS_arm := -Wl,--hash-style=both
diff --git a/liblog/event_tag_map.c b/liblog/event_tag_map.c
index bea99aa..870c69a 100644
--- a/liblog/event_tag_map.c
+++ b/liblog/event_tag_map.c
@@ -24,6 +24,8 @@
 #include <log/event_tag_map.h>
 #include <log/log.h>
 
+#include "log_cdefs.h"
+
 #define OUT_TAG "EventTagMap"
 
 /*
@@ -61,7 +63,7 @@
  * We create a private mapping because we want to terminate the log tag
  * strings with '\0'.
  */
-EventTagMap* android_openEventTagMap(const char* fileName)
+LIBLOG_ABI_PUBLIC EventTagMap* android_openEventTagMap(const char* fileName)
 {
     EventTagMap* newTagMap;
     off_t end;
@@ -109,7 +111,7 @@
 /*
  * Close the map.
  */
-void android_closeEventTagMap(EventTagMap* map)
+LIBLOG_ABI_PUBLIC void android_closeEventTagMap(EventTagMap* map)
 {
     if (map == NULL)
         return;
@@ -123,7 +125,8 @@
  *
  * The entries are sorted by tag number, so we can do a binary search.
  */
-const char* android_lookupEventTag(const EventTagMap* map, int tag)
+LIBLOG_ABI_PUBLIC const char* android_lookupEventTag(const EventTagMap* map,
+                                                     int tag)
 {
     int hi, lo, mid;
 
diff --git a/liblog/fake_log_device.c b/liblog/fake_log_device.c
index aa88bed..c73e03e 100644
--- a/liblog/fake_log_device.c
+++ b/liblog/fake_log_device.c
@@ -19,23 +19,19 @@
  * passed on to the underlying (fake) log device.  When not in the
  * simulator, messages are printed to stderr.
  */
-#include "fake_log_device.h"
-
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
+#if !defined(_WIN32)
+#include <pthread.h>
+#endif
 #include <stdlib.h>
 #include <string.h>
 
 #include <log/logd.h>
 
-#if !defined(_WIN32)
-#include <pthread.h>
-#endif
-
-#ifndef __unused
-#define __unused __attribute__((__unused__))
-#endif
+#include "fake_log_device.h"
+#include "log_cdefs.h"
 
 #define kMaxTagLen  16      /* from the long-dead utils/Log.cpp */
 
@@ -512,7 +508,7 @@
         }
         numLines -= 1;
     }
-    
+
     /*
      * Write the entire message to the log file with a single writev() call.
      * We need to use this rather than a collection of printf()s on a FILE*
@@ -531,10 +527,10 @@
         int cc = writev(fileno(stderr), vec, v-vec);
 
         if (cc == totalLen) break;
-        
+
         if (cc < 0) {
             if(errno == EINTR) continue;
-            
+
                 /* can't really log the failure; for now, throw out a stderr */
             fprintf(stderr, "+++ LOG: write failed (errno=%d)\n", errno);
             break;
@@ -683,7 +679,7 @@
     }
 }
 
-int fakeLogOpen(const char *pathName, int flags)
+LIBLOG_HIDDEN int fakeLogOpen(const char *pathName, int flags)
 {
     if (redirectOpen == NULL) {
         setRedirects();
@@ -702,19 +698,22 @@
  * call is in the exit handler. Logging can continue in the exit handler to
  * help debug HOST tools ...
  */
-int fakeLogClose(int fd)
+LIBLOG_HIDDEN int fakeLogClose(int fd)
 {
     /* Assume that open() was called first. */
     return redirectClose(fd);
 }
 
-ssize_t fakeLogWritev(int fd, const struct iovec* vector, int count)
+LIBLOG_HIDDEN ssize_t fakeLogWritev(int fd,
+                                    const struct iovec* vector, int count)
 {
     /* Assume that open() was called first. */
     return redirectWritev(fd, vector, count);
 }
 
-int __android_log_is_loggable(int prio, const char *tag __unused, int def)
+LIBLOG_ABI_PUBLIC int __android_log_is_loggable(int prio,
+                                                const char *tag __unused,
+                                                int def)
 {
     int logLevel = def;
     return logLevel >= 0 && prio >= logLevel;
diff --git a/liblog/fake_log_device.h b/liblog/fake_log_device.h
index 9d168cd..672b446 100644
--- a/liblog/fake_log_device.h
+++ b/liblog/fake_log_device.h
@@ -19,10 +19,13 @@
 
 #include <sys/types.h>
 
+#include "log_cdefs.h"
+
 struct iovec;
 
-int fakeLogOpen(const char *pathName, int flags);
-int fakeLogClose(int fd);
-ssize_t fakeLogWritev(int fd, const struct iovec* vector, int count);
+LIBLOG_HIDDEN int fakeLogOpen(const char *pathName, int flags);
+LIBLOG_HIDDEN int fakeLogClose(int fd);
+LIBLOG_HIDDEN ssize_t fakeLogWritev(int fd,
+                                    const struct iovec* vector, int count);
 
 #endif // _LIBLOG_FAKE_LOG_DEVICE_H
diff --git a/liblog/log_cdefs.h b/liblog/log_cdefs.h
new file mode 100644
index 0000000..3a52625
--- /dev/null
+++ b/liblog/log_cdefs.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef _LIBLOG_CDEFS_H__
+#define _LIBLOG_CDEFS_H__
+
+#include <sys/cdefs.h>
+
+/* Declare this library function hidden and internal */
+#if defined(_WIN32)
+#define LIBLOG_HIDDEN
+#else
+#define LIBLOG_HIDDEN __attribute__((visibility("hidden")))
+#endif
+
+/* Declare this library function visible and external */
+#if defined(_WIN32)
+#define LIBLOG_ABI_PUBLIC
+#else
+#define LIBLOG_ABI_PUBLIC __attribute__((visibility("default")))
+#endif
+
+/* Declare this library function visible but private */
+#define LIBLOG_ABI_PRIVATE LIBLOG_ABI_PUBLIC
+
+/*
+ * Declare this library function as reimplementation.
+ * Prevent circular dependencies, but allow _real_ library to hijack
+ */
+#if defined(_WIN32)
+#define LIBLOG_WEAK static /* Accept that it is totally private */
+#else
+#define LIBLOG_WEAK __attribute__((weak,visibility("default")))
+#endif
+
+/* Unused argument. For C code only, remove symbol name for C++ */
+#ifndef __unused
+#define __unused        __attribute__((__unused__))
+#endif
+
+#endif /* _LIBLOG_CDEFS_H__ */
diff --git a/liblog/log_event_list.c b/liblog/log_event_list.c
index 2213f21..a77c56e 100644
--- a/liblog/log_event_list.c
+++ b/liblog/log_event_list.c
@@ -25,6 +25,8 @@
 #include <log/log.h>
 #include <log/logger.h>
 
+#include "log_cdefs.h"
+
 #define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(int32_t))
 
 typedef struct {
@@ -43,7 +45,7 @@
     uint8_t storage[LOGGER_ENTRY_MAX_PAYLOAD];
 } android_log_context_internal;
 
-android_log_context create_android_logger(uint32_t tag) {
+LIBLOG_ABI_PUBLIC android_log_context create_android_logger(uint32_t tag) {
     size_t needed, i;
     android_log_context_internal *context;
 
@@ -65,7 +67,9 @@
     return (android_log_context)context;
 }
 
-android_log_context create_android_log_parser(const char *msg, size_t len) {
+LIBLOG_ABI_PUBLIC android_log_context create_android_log_parser(
+        const char *msg,
+        size_t len) {
     android_log_context_internal *context;
     size_t i;
 
@@ -81,7 +85,7 @@
     return (android_log_context)context;
 }
 
-int android_log_destroy(android_log_context *ctx) {
+LIBLOG_ABI_PUBLIC int android_log_destroy(android_log_context *ctx) {
     android_log_context_internal *context;
 
     context = (android_log_context_internal *)*ctx;
@@ -94,7 +98,7 @@
     return 0;
 }
 
-int android_log_write_list_begin(android_log_context ctx) {
+LIBLOG_ABI_PUBLIC int android_log_write_list_begin(android_log_context ctx) {
     size_t needed;
     android_log_context_internal *context;
 
@@ -137,7 +141,8 @@
     buf[3] = (val >> 24) & 0xFF;
 }
 
-int android_log_write_int32(android_log_context ctx, int32_t value) {
+LIBLOG_ABI_PUBLIC int android_log_write_int32(android_log_context ctx,
+                                              int32_t value) {
     size_t needed;
     android_log_context_internal *context;
 
@@ -172,7 +177,8 @@
     buf[7] = (val >> 56) & 0xFF;
 }
 
-int android_log_write_int64(android_log_context ctx, int64_t value) {
+LIBLOG_ABI_PUBLIC int android_log_write_int64(android_log_context ctx,
+                                              int64_t value) {
     size_t needed;
     android_log_context_internal *context;
 
@@ -195,8 +201,9 @@
     return 0;
 }
 
-int android_log_write_string8_len(android_log_context ctx,
-                                  const char *value, size_t maxlen) {
+LIBLOG_ABI_PUBLIC int android_log_write_string8_len(android_log_context ctx,
+                                                    const char *value,
+                                                    size_t maxlen) {
     size_t needed;
     ssize_t len;
     android_log_context_internal *context;
@@ -231,11 +238,13 @@
     return len;
 }
 
-int android_log_write_string8(android_log_context ctx, const char *value) {
+LIBLOG_ABI_PUBLIC int android_log_write_string8(android_log_context ctx,
+                                                const char *value) {
     return android_log_write_string8_len(ctx, value, MAX_EVENT_PAYLOAD);
 }
 
-int android_log_write_float32(android_log_context ctx, float value) {
+LIBLOG_ABI_PUBLIC int android_log_write_float32(android_log_context ctx,
+                                                float value) {
     size_t needed;
     uint32_t ivalue;
     android_log_context_internal *context;
@@ -260,7 +269,7 @@
     return 0;
 }
 
-int android_log_write_list_end(android_log_context ctx) {
+LIBLOG_ABI_PUBLIC int android_log_write_list_end(android_log_context ctx) {
     android_log_context_internal *context;
 
     context = (android_log_context_internal *)ctx;
@@ -290,7 +299,8 @@
 /*
  * Logs the list of elements to the event log.
  */
-int android_log_write_list(android_log_context ctx, log_id_t id) {
+LIBLOG_ABI_PUBLIC int android_log_write_list(android_log_context ctx,
+                                             log_id_t id) {
     android_log_context_internal *context;
     const char *msg;
     ssize_t len;
@@ -518,10 +528,12 @@
     }
 }
 
-android_log_list_element android_log_read_next(android_log_context ctx) {
+LIBLOG_ABI_PUBLIC android_log_list_element android_log_read_next(
+        android_log_context ctx) {
     return android_log_read_next_internal(ctx, 0);
 }
 
-android_log_list_element android_log_peek_next(android_log_context ctx) {
+LIBLOG_ABI_PUBLIC android_log_list_element android_log_peek_next(
+        android_log_context ctx) {
     return android_log_read_next_internal(ctx, 1);
 }
diff --git a/liblog/log_event_write.c b/liblog/log_event_write.c
index ad42edd..3535b94 100644
--- a/liblog/log_event_write.c
+++ b/liblog/log_event_write.c
@@ -18,10 +18,15 @@
 
 #include <log/log.h>
 
+#include "log_cdefs.h"
+
 #define MAX_SUBTAG_LEN 32
 
-int __android_log_error_write(int tag, const char *subTag, int32_t uid,
-                              const char *data, uint32_t dataLen)
+LIBLOG_ABI_PUBLIC int __android_log_error_write(
+        int tag,
+        const char *subTag,
+        int32_t uid,
+        const char *data, uint32_t dataLen)
 {
     int ret = -EINVAL;
 
diff --git a/liblog/log_is_loggable.c b/liblog/log_is_loggable.c
index 2f8f886..47fde20 100644
--- a/liblog/log_is_loggable.c
+++ b/liblog/log_is_loggable.c
@@ -23,6 +23,8 @@
 
 #include <android/log.h>
 
+#include "log_cdefs.h"
+
 static pthread_mutex_t lock_loggable = PTHREAD_MUTEX_INITIALIZER;
 
 static int lock()
@@ -250,7 +252,8 @@
     return default_prio;
 }
 
-int __android_log_is_loggable(int prio, const char *tag, int default_prio)
+LIBLOG_ABI_PUBLIC int __android_log_is_loggable(int prio, const char *tag,
+                                                int default_prio)
 {
     int logLevel = __android_log_level(tag, default_prio);
     return logLevel >= 0 && prio >= logLevel;
@@ -315,7 +318,7 @@
  * Timestamp state generally remains constant, but can change at any time
  * to handle developer requirements.
  */
-clockid_t android_log_clockid()
+LIBLOG_ABI_PUBLIC clockid_t android_log_clockid()
 {
     static struct cache2 clockid = {
         PTHREAD_MUTEX_INITIALIZER,
@@ -343,7 +346,7 @@
     return (c != BOOLEAN_FALSE) && c && (self->cache_persist.c == BOOLEAN_TRUE);
 }
 
-int __android_log_security()
+LIBLOG_ABI_PUBLIC int __android_log_security()
 {
     static struct cache2 security = {
         PTHREAD_MUTEX_INITIALIZER,
diff --git a/liblog/log_read.c b/liblog/log_read.c
index fc63d2c..4b83944 100644
--- a/liblog/log_read.c
+++ b/liblog/log_read.c
@@ -24,7 +24,6 @@
 #define NOMINMAX /* for windows to suppress definition of min in stdlib.h */
 #include <stdlib.h>
 #include <string.h>
-#include <sys/cdefs.h>
 #include <unistd.h>
 
 #include <cutils/list.h>
@@ -34,23 +33,16 @@
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
+#include "log_cdefs.h"
+
 /* branchless on many architectures. */
 #define min(x,y) ((y) ^ (((x) ^ (y)) & -((x) < (y))))
 
-#if defined(_WIN32)
-#define WEAK static
-#else
-#define WEAK __attribute__((weak))
-#endif
-#ifndef __unused
-#define __unused __attribute__((unused))
-#endif
-
 /* Private copy of ../libcutils/socket_local_client.c prevent library loops */
 
 #if defined(_WIN32)
 
-int WEAK socket_local_client(const char *name, int namespaceId, int type)
+LIBLOG_WEAK int socket_local_client(const char *name, int namespaceId, int type)
 {
     errno = ENOSYS;
     return -ENOSYS;
@@ -71,8 +63,9 @@
 #define LISTEN_BACKLOG 4
 
 /* Documented in header file. */
-int WEAK socket_make_sockaddr_un(const char *name, int namespaceId,
-                                 struct sockaddr_un *p_addr, socklen_t *alen)
+LIBLOG_WEAK int socket_make_sockaddr_un(const char *name, int namespaceId,
+                                        struct sockaddr_un *p_addr,
+                                        socklen_t *alen)
 {
     memset (p_addr, 0, sizeof (*p_addr));
     size_t namelen;
@@ -151,8 +144,8 @@
  *
  * Used by AndroidSocketImpl
  */
-int WEAK socket_local_client_connect(int fd, const char *name, int namespaceId,
-                                     int type __unused)
+LIBLOG_WEAK int socket_local_client_connect(int fd, const char *name,
+                                            int namespaceId, int type __unused)
 {
     struct sockaddr_un addr;
     socklen_t alen;
@@ -178,7 +171,7 @@
  * connect to peer named "name"
  * returns fd or -1 on error
  */
-int WEAK socket_local_client(const char *name, int namespaceId, int type)
+LIBLOG_WEAK int socket_local_client(const char *name, int namespaceId, int type)
 {
     int s;
 
@@ -212,7 +205,7 @@
     [LOG_ID_KERNEL] = "kernel",
 };
 
-const char *android_log_id_to_name(log_id_t log_id)
+LIBLOG_ABI_PUBLIC const char *android_log_id_to_name(log_id_t log_id)
 {
     if (log_id >= LOG_ID_MAX) {
         log_id = LOG_ID_MAIN;
@@ -220,7 +213,7 @@
     return LOG_NAME[log_id];
 }
 
-log_id_t android_name_to_log_id(const char *logName)
+LIBLOG_ABI_PUBLIC log_id_t android_name_to_log_id(const char *logName)
 {
     const char *b;
     int ret;
@@ -275,7 +268,7 @@
 /* android_logger_alloc unimplemented, no use case */
 
 /* method for getting the associated sublog id */
-log_id_t android_logger_get_id(struct logger *logger)
+LIBLOG_ABI_PUBLIC log_id_t android_logger_get_id(struct logger *logger)
 {
     return logger->id;
 }
@@ -409,7 +402,7 @@
     return last_uid = uid;
 }
 
-int android_logger_clear(struct logger *logger)
+LIBLOG_ABI_PUBLIC int android_logger_clear(struct logger *logger)
 {
     char buf[512];
 
@@ -425,7 +418,7 @@
 }
 
 /* returns the total size of the log's ring buffer */
-long android_logger_get_log_size(struct logger *logger)
+LIBLOG_ABI_PUBLIC long android_logger_get_log_size(struct logger *logger)
 {
     char buf[512];
 
@@ -441,7 +434,8 @@
     return atol(buf);
 }
 
-int android_logger_set_log_size(struct logger *logger, unsigned long size)
+LIBLOG_ABI_PUBLIC int android_logger_set_log_size(struct logger *logger,
+                                                  unsigned long size)
 {
     char buf[512];
 
@@ -455,7 +449,8 @@
  * returns the readable size of the log's ring buffer (that is, amount of the
  * log consumed)
  */
-long android_logger_get_log_readable_size(struct logger *logger)
+LIBLOG_ABI_PUBLIC long android_logger_get_log_readable_size(
+        struct logger *logger)
 {
     char buf[512];
 
@@ -474,16 +469,18 @@
 /*
  * returns the logger version
  */
-int android_logger_get_log_version(struct logger *logger __unused)
+LIBLOG_ABI_PUBLIC int android_logger_get_log_version(
+        struct logger *logger __unused)
 {
-    return 3;
+    return 4;
 }
 
 /*
  * returns statistics
  */
-ssize_t android_logger_get_statistics(struct logger_list *logger_list,
-                                      char *buf, size_t len)
+LIBLOG_ABI_PUBLIC ssize_t android_logger_get_statistics(
+        struct logger_list *logger_list,
+        char *buf, size_t len)
 {
     struct logger *logger;
     char *cp = buf;
@@ -509,14 +506,16 @@
     return send_log_msg(NULL, NULL, buf, len);
 }
 
-ssize_t android_logger_get_prune_list(struct logger_list *logger_list __unused,
-                                      char *buf, size_t len)
+LIBLOG_ABI_PUBLIC ssize_t android_logger_get_prune_list(
+        struct logger_list *logger_list __unused,
+        char *buf, size_t len)
 {
     return send_log_msg(NULL, "getPruneList", buf, len);
 }
 
-int android_logger_set_prune_list(struct logger_list *logger_list __unused,
-                                  char *buf, size_t len)
+LIBLOG_ABI_PUBLIC int android_logger_set_prune_list(
+        struct logger_list *logger_list __unused,
+        char *buf, size_t len)
 {
     const char cmd[] = "setPruneList ";
     const size_t cmdlen = sizeof(cmd) - 1;
@@ -531,9 +530,10 @@
     return check_log_success(buf, send_log_msg(NULL, NULL, buf, len));
 }
 
-struct logger_list *android_logger_list_alloc(int mode,
-                                              unsigned int tail,
-                                              pid_t pid)
+LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_alloc(
+        int mode,
+        unsigned int tail,
+        pid_t pid)
 {
     struct logger_list *logger_list;
 
@@ -553,9 +553,10 @@
     return logger_list;
 }
 
-struct logger_list *android_logger_list_alloc_time(int mode,
-                                                   log_time start,
-                                                   pid_t pid)
+LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_alloc_time(
+        int mode,
+        log_time start,
+        pid_t pid)
 {
     struct logger_list *logger_list;
 
@@ -578,8 +579,9 @@
 /* android_logger_list_unregister unimplemented, no use case */
 
 /* Open the named log and add it to the logger list */
-struct logger *android_logger_open(struct logger_list *logger_list,
-                                   log_id_t id)
+LIBLOG_ABI_PUBLIC struct logger *android_logger_open(
+        struct logger_list *logger_list,
+        log_id_t id)
 {
     struct logger *logger;
 
@@ -610,10 +612,11 @@
 }
 
 /* Open the single named log and make it part of a new logger list */
-struct logger_list *android_logger_list_open(log_id_t id,
-                                             int mode,
-                                             unsigned int tail,
-                                             pid_t pid)
+LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_open(
+        log_id_t id,
+        int mode,
+        unsigned int tail,
+        pid_t pid)
 {
     struct logger_list *logger_list = android_logger_list_alloc(mode, tail, pid);
     if (!logger_list) {
@@ -751,8 +754,9 @@
 }
 
 /* Read from the selected logs */
-int android_logger_list_read(struct logger_list *logger_list,
-                             struct log_msg *log_msg)
+LIBLOG_ABI_PUBLIC int android_logger_list_read(
+        struct logger_list *logger_list,
+        struct log_msg *log_msg)
 {
     int ret, e;
     struct logger *logger;
@@ -892,7 +896,8 @@
 }
 
 /* Close all the logs */
-void android_logger_list_free(struct logger_list *logger_list)
+LIBLOG_ABI_PUBLIC void android_logger_list_free(
+        struct logger_list *logger_list)
 {
     if (logger_list == NULL) {
         return;
diff --git a/liblog/log_time.cpp b/liblog/log_time.cpp
index 9d5ea0e..b6af222 100644
--- a/liblog/log_time.cpp
+++ b/liblog/log_time.cpp
@@ -18,16 +18,17 @@
 #include <limits.h>
 #include <stdio.h>
 #include <string.h>
-#include <sys/cdefs.h>
 
 #include <log/log_read.h>
 
-const char log_time::default_format[] = "%m-%d %H:%M:%S.%q";
-const timespec log_time::EPOCH = { 0, 0 };
+#include "log_cdefs.h"
+
+LIBLOG_ABI_PRIVATE const char log_time::default_format[] = "%m-%d %H:%M:%S.%q";
+LIBLOG_ABI_PRIVATE const timespec log_time::EPOCH = { 0, 0 };
 
 // Add %#q for fractional seconds to standard strptime function
 
-char *log_time::strptime(const char *s, const char *format) {
+LIBLOG_ABI_PRIVATE char *log_time::strptime(const char *s, const char *format) {
     time_t now;
 #ifdef __linux__
     *this = log_time(CLOCK_REALTIME);
@@ -133,7 +134,7 @@
     return ret;
 }
 
-log_time log_time::operator-= (const timespec &T) {
+LIBLOG_ABI_PRIVATE log_time log_time::operator-= (const timespec &T) {
     // No concept of negative time, clamp to EPOCH
     if (*this <= T) {
         return *this = EPOCH;
@@ -150,7 +151,7 @@
     return *this;
 }
 
-log_time log_time::operator+= (const timespec &T) {
+LIBLOG_ABI_PRIVATE log_time log_time::operator+= (const timespec &T) {
     this->tv_nsec += (unsigned long int)T.tv_nsec;
     if (this->tv_nsec >= NS_PER_SEC) {
         this->tv_nsec -= NS_PER_SEC;
@@ -161,7 +162,7 @@
     return *this;
 }
 
-log_time log_time::operator-= (const log_time &T) {
+LIBLOG_ABI_PRIVATE log_time log_time::operator-= (const log_time &T) {
     // No concept of negative time, clamp to EPOCH
     if (*this <= T) {
         return *this = EPOCH;
@@ -178,7 +179,7 @@
     return *this;
 }
 
-log_time log_time::operator+= (const log_time &T) {
+LIBLOG_ABI_PRIVATE log_time log_time::operator+= (const log_time &T) {
     this->tv_nsec += T.tv_nsec;
     if (this->tv_nsec >= NS_PER_SEC) {
         this->tv_nsec -= NS_PER_SEC;
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index b173d1a..85a4aab 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -46,6 +46,8 @@
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
+#include "log_cdefs.h"
+
 #define LOG_BUF_SIZE 1024
 
 #if FAKE_LOG_DEVICE
@@ -56,10 +58,6 @@
 static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr);
 static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init;
 
-#ifndef __unused
-#define __unused  __attribute__((__unused__))
-#endif
-
 #if !defined(_WIN32)
 static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
 
@@ -106,7 +104,7 @@
     kLogUninitialized, kLogNotAvailable, kLogAvailable
 } g_log_status = kLogUninitialized;
 
-int __android_log_dev_available(void)
+LIBLOG_ABI_PUBLIC int __android_log_dev_available()
 {
     if (g_log_status == kLogUninitialized) {
         if (access("/dev/socket/logdw", W_OK) == 0)
@@ -485,7 +483,7 @@
     [LOG_ID_KERNEL] = "kernel",
 };
 
-const char *android_log_id_to_name(log_id_t log_id)
+LIBLOG_ABI_PUBLIC const char *android_log_id_to_name(log_id_t log_id)
 {
     if (log_id >= LOG_ID_MAX) {
         log_id = LOG_ID_MAIN;
@@ -520,12 +518,14 @@
     return write_to_log(log_id, vec, nr);
 }
 
-int __android_log_write(int prio, const char *tag, const char *msg)
+LIBLOG_ABI_PUBLIC int __android_log_write(int prio, const char *tag,
+                                          const char *msg)
 {
     return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
 }
 
-int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg)
+LIBLOG_ABI_PUBLIC int __android_log_buf_write(int bufID, int prio,
+                                              const char *tag, const char *msg)
 {
     struct iovec vec[3];
     char tmp_tag[32];
@@ -566,7 +566,8 @@
     return write_to_log(bufID, vec, 3);
 }
 
-int __android_log_vprint(int prio, const char *tag, const char *fmt, va_list ap)
+LIBLOG_ABI_PUBLIC int __android_log_vprint(int prio, const char *tag,
+                                           const char *fmt, va_list ap)
 {
     char buf[LOG_BUF_SIZE];
 
@@ -575,7 +576,8 @@
     return __android_log_write(prio, tag, buf);
 }
 
-int __android_log_print(int prio, const char *tag, const char *fmt, ...)
+LIBLOG_ABI_PUBLIC int __android_log_print(int prio, const char *tag,
+                                          const char *fmt, ...)
 {
     va_list ap;
     char buf[LOG_BUF_SIZE];
@@ -587,7 +589,9 @@
     return __android_log_write(prio, tag, buf);
 }
 
-int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...)
+LIBLOG_ABI_PUBLIC int __android_log_buf_print(int bufID, int prio,
+                                              const char *tag,
+                                              const char *fmt, ...)
 {
     va_list ap;
     char buf[LOG_BUF_SIZE];
@@ -599,8 +603,10 @@
     return __android_log_buf_write(bufID, prio, tag, buf);
 }
 
-void __android_log_assert(const char *cond, const char *tag,
-                          const char *fmt, ...)
+LIBLOG_ABI_PUBLIC void __android_log_assert(
+        const char *cond,
+        const char *tag,
+        const char *fmt, ...)
 {
     char buf[LOG_BUF_SIZE];
 
@@ -625,7 +631,8 @@
     /* NOTREACHED */
 }
 
-int __android_log_bwrite(int32_t tag, const void *payload, size_t len)
+LIBLOG_ABI_PUBLIC int __android_log_bwrite(int32_t tag,
+                                           const void *payload, size_t len)
 {
     struct iovec vec[2];
 
@@ -637,7 +644,9 @@
     return write_to_log(LOG_ID_EVENTS, vec, 2);
 }
 
-int __android_log_security_bwrite(int32_t tag, const void *payload, size_t len)
+LIBLOG_ABI_PUBLIC int __android_log_security_bwrite(int32_t tag,
+                                                    const void *payload,
+                                                    size_t len)
 {
     struct iovec vec[2];
 
@@ -654,8 +663,8 @@
  * for the general case where we're generating lists of stuff, but very
  * handy if we just want to dump an integer into the log.
  */
-int __android_log_btwrite(int32_t tag, char type, const void *payload,
-                          size_t len)
+LIBLOG_ABI_PUBLIC int __android_log_btwrite(int32_t tag, char type,
+                                            const void *payload, size_t len)
 {
     struct iovec vec[3];
 
@@ -673,7 +682,7 @@
  * Like __android_log_bwrite, but used for writing strings to the
  * event log.
  */
-int __android_log_bswrite(int32_t tag, const char *payload)
+LIBLOG_ABI_PUBLIC int __android_log_bswrite(int32_t tag, const char *payload)
 {
     struct iovec vec[4];
     char type = EVENT_TYPE_STRING;
@@ -695,7 +704,8 @@
  * Like __android_log_security_bwrite, but used for writing strings to the
  * security log.
  */
-int __android_log_security_bswrite(int32_t tag, const char *payload)
+LIBLOG_ABI_PUBLIC int __android_log_security_bswrite(int32_t tag,
+                                                     const char *payload)
 {
     struct iovec vec[4];
     char type = EVENT_TYPE_STRING;
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 4ef62a1..19a3e27 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -34,12 +34,11 @@
 #include <log/logprint.h>
 #include <private/android_filesystem_config.h>
 
+#include "log_cdefs.h"
+
 #define MS_PER_NSEC 1000000
 #define US_PER_NSEC 1000
 
-/* open coded fragment, prevent circular dependencies */
-#define WEAK static
-
 typedef struct FilterInfo_t {
     char *mTag;
     android_LogPriority mPri;
@@ -185,13 +184,15 @@
  * returns 1 if this log line should be printed based on its priority
  * and tag, and 0 if it should not
  */
-int android_log_shouldPrintLine (
-        AndroidLogFormat *p_format, const char *tag, android_LogPriority pri)
+LIBLOG_ABI_PUBLIC int android_log_shouldPrintLine (
+        AndroidLogFormat *p_format,
+        const char *tag,
+        android_LogPriority pri)
 {
     return pri >= filterPriForTag(p_format, tag);
 }
 
-AndroidLogFormat *android_log_format_new()
+LIBLOG_ABI_PUBLIC AndroidLogFormat *android_log_format_new()
 {
     AndroidLogFormat *p_ret;
 
@@ -213,7 +214,7 @@
 
 static list_declare(convertHead);
 
-void android_log_format_free(AndroidLogFormat *p_format)
+LIBLOG_ABI_PUBLIC void android_log_format_free(AndroidLogFormat *p_format)
 {
     FilterInfo *p_info, *p_info_old;
 
@@ -236,7 +237,8 @@
     }
 }
 
-int android_log_setPrintFormat(AndroidLogFormat *p_format,
+LIBLOG_ABI_PUBLIC int android_log_setPrintFormat(
+        AndroidLogFormat *p_format,
         AndroidLogPrintFormat format)
 {
     switch (format) {
@@ -277,7 +279,8 @@
 /**
  * Returns FORMAT_OFF on invalid string
  */
-AndroidLogPrintFormat android_log_formatFromString(const char * formatString)
+LIBLOG_ABI_PUBLIC AndroidLogPrintFormat android_log_formatFromString(
+        const char * formatString)
 {
     static AndroidLogPrintFormat format;
 
@@ -341,7 +344,8 @@
  * Assumes single threaded execution
  */
 
-int android_log_addFilterRule(AndroidLogFormat *p_format,
+LIBLOG_ABI_PUBLIC int android_log_addFilterRule(
+        AndroidLogFormat *p_format,
         const char *filterExpression)
 {
     size_t tagNameLength;
@@ -419,7 +423,8 @@
  *
  */
 
-int android_log_addFilterString(AndroidLogFormat *p_format,
+LIBLOG_ABI_PUBLIC int android_log_addFilterString(
+        AndroidLogFormat *p_format,
         const char *filterString)
 {
     char *filterStringCopy = strdup (filterString);
@@ -453,8 +458,9 @@
  * Returns 0 on success and -1 on invalid wire format (entry will be
  * in unspecified state)
  */
-int android_log_processLogBuffer(struct logger_entry *buf,
-                                 AndroidLogEntry *entry)
+LIBLOG_ABI_PUBLIC int android_log_processLogBuffer(
+        struct logger_entry *buf,
+        AndroidLogEntry *entry)
 {
     entry->tv_sec = buf->sec;
     entry->tv_nsec = buf->nsec;
@@ -734,9 +740,11 @@
  * it however we choose, which means we can't really use a fixed-size buffer
  * here.
  */
-int android_log_processBinaryLogBuffer(struct logger_entry *buf,
-    AndroidLogEntry *entry, const EventTagMap* map, char* messageBuf,
-    int messageBufLen)
+LIBLOG_ABI_PUBLIC int android_log_processBinaryLogBuffer(
+        struct logger_entry *buf,
+        AndroidLogEntry *entry,
+        const EventTagMap *map,
+        char *messageBuf, int messageBufLen)
 {
     size_t inCount;
     unsigned int tagIndex;
@@ -852,7 +860,7 @@
  * _also_ be part of libutils/Unicode.cpp if its usefullness needs to
  * propagate globally.
  */
-WEAK ssize_t utf8_character_length(const char *src, size_t len)
+LIBLOG_WEAK ssize_t utf8_character_length(const char *src, size_t len)
 {
     const char *cur = src;
     const char first_char = *cur++;
@@ -956,7 +964,7 @@
     return p - begin;
 }
 
-char *readSeconds(char *e, struct timespec *t)
+static char *readSeconds(char *e, struct timespec *t)
 {
     unsigned long multiplier;
     char *p;
@@ -1243,12 +1251,12 @@
  * Returns NULL on malloc error
  */
 
-char *android_log_formatLogLine (
-    AndroidLogFormat *p_format,
-    char *defaultBuffer,
-    size_t defaultBufferSize,
-    const AndroidLogEntry *entry,
-    size_t *p_outLength)
+LIBLOG_ABI_PUBLIC char *android_log_formatLogLine (
+        AndroidLogFormat *p_format,
+        char *defaultBuffer,
+        size_t defaultBufferSize,
+        const AndroidLogEntry *entry,
+        size_t *p_outLength)
 {
 #if !defined(_WIN32)
     struct tm tmBuf;
@@ -1526,10 +1534,10 @@
  * Returns count bytes written
  */
 
-int android_log_printLogLine(
-    AndroidLogFormat *p_format,
-    int fd,
-    const AndroidLogEntry *entry)
+LIBLOG_ABI_PUBLIC int android_log_printLogLine(
+        AndroidLogFormat *p_format,
+        int fd,
+        const AndroidLogEntry *entry)
 {
     int ret;
     char defaultBuffer[512];
diff --git a/liblog/uio.c b/liblog/uio.c
index f77cc49..d0184dc 100644
--- a/liblog/uio.c
+++ b/liblog/uio.c
@@ -16,17 +16,20 @@
 
 #if defined(_WIN32)
 
-#include <log/uio.h>
 #include <unistd.h>
 
-int  readv( int  fd, struct iovec*  vecs, int  count )
+#include <log/uio.h>
+
+#include "log_cdefs.h"
+
+LIBLOG_ABI_PUBLIC int readv(int fd, struct iovec *vecs, int count)
 {
     int   total = 0;
 
     for ( ; count > 0; count--, vecs++ ) {
         char*  buf = vecs->iov_base;
         int    len = vecs->iov_len;
-        
+
         while (len > 0) {
             int  ret = read( fd, buf, len );
             if (ret < 0) {
@@ -46,14 +49,14 @@
     return total;
 }
 
-int  writev( int  fd, const struct iovec*  vecs, int  count )
+LIBLOG_ABI_PUBLIC int writev(int fd, const struct iovec *vecs, int count)
 {
     int   total = 0;
 
     for ( ; count > 0; count--, vecs++ ) {
         const char*  buf = vecs->iov_base;
         int          len = vecs->iov_len;
-        
+
         while (len > 0) {
             int  ret = write( fd, buf, len );
             if (ret < 0) {
@@ -69,7 +72,7 @@
             len   -= ret;
         }
     }
-Exit:    
+Exit:
     return total;
 }
 
diff --git a/mkbootimg/bootimg.h b/mkbootimg/bootimg.h
index 2bd8230..5ab6195 100644
--- a/mkbootimg/bootimg.h
+++ b/mkbootimg/bootimg.h
@@ -43,11 +43,7 @@
 
     uint32_t tags_addr;    /* physical addr for kernel tags */
     uint32_t page_size;    /* flash page size we assume */
-
-    /* operating system version; "1.2.34" -> 010234 */
-    uint32_t os_version;
-    /* operating system patch level; "2016-01-01" -> 20160101 */
-    uint32_t os_patch_level;
+    uint32_t unused[2];    /* future expansion: should be 0 */
 
     uint8_t name[BOOT_NAME_SIZE]; /* asciiz product name */
 
diff --git a/mkbootimg/mkbootimg b/mkbootimg/mkbootimg
index be342c9..f95d703 100755
--- a/mkbootimg/mkbootimg
+++ b/mkbootimg/mkbootimg
@@ -20,7 +20,6 @@
 from struct import pack
 from hashlib import sha1
 import sys
-import re
 
 def filesize(f):
     if f is None:
@@ -48,7 +47,7 @@
 def write_header(args):
     BOOT_MAGIC = 'ANDROID!'.encode()
     args.output.write(pack('8s', BOOT_MAGIC))
-    args.output.write(pack('10I',
+    args.output.write(pack('8I',
         filesize(args.kernel),                          # size in bytes
         args.base + args.kernel_offset,                 # physical load addr
         filesize(args.ramdisk),                         # size in bytes
@@ -56,9 +55,8 @@
         filesize(args.second),                          # size in bytes
         args.base + args.second_offset,                 # physical load addr
         args.base + args.tags_offset,                   # physical addr for kernel tags
-        args.pagesize,                                  # flash page size we assume
-        args.os_version,                                # operating system version
-        args.os_patch_level))                           # security patch level
+        args.pagesize))                                 # flash page size we assume
+    args.output.write(pack('8x'))                       # future expansion: should be 0
     args.output.write(pack('16s', args.board.encode())) # asciiz product name
     args.output.write(pack('512s', args.cmdline[:512].encode()))
 
@@ -99,18 +97,6 @@
 def parse_int(x):
     return int(x, 0)
 
-def match_to_int(x):
-    if (x and x.lastindex == 3):
-        return (parse_int(x.group(3)) +
-                parse_int(x.group(2)) * 100 +
-                parse_int(x.group(1)) * 10000)
-    return 0
-
-def parse_os_version(x):
-    return match_to_int(re.search(r'^(\d+)\.(\d{1,2})\.(\d{1,2})', x))
-
-def parse_os_patch_level(x):
-    return match_to_int(re.search(r'^(\d{4,})-(\d{2})-(\d{2})', x))
 
 def parse_cmdline():
     parser = ArgumentParser()
@@ -125,10 +111,6 @@
     parser.add_argument('--ramdisk_offset', help='ramdisk offset', type=parse_int, default=0x01000000)
     parser.add_argument('--second_offset', help='2nd bootloader offset', type=parse_int,
                         default=0x00f00000)
-    parser.add_argument('--os_version', help='operating system version', type=parse_os_version,
-                        default=0)
-    parser.add_argument('--os_patch_level', help='operating system patch level',
-                        type=parse_os_patch_level, default=0)
     parser.add_argument('--tags_offset', help='tags offset', type=parse_int, default=0x00000100)
     parser.add_argument('--board', help='board name', default='', action=ValidateStrLenAction,
                         maxlen=16)