Merge "adb: `adbd` uses shared libraries."
diff --git a/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h
index a9cfce4..c564271 100644
--- a/libbacktrace/include/backtrace/BacktraceMap.h
+++ b/libbacktrace/include/backtrace/BacktraceMap.h
@@ -31,6 +31,7 @@
 
 #include <deque>
 #include <iterator>
+#include <memory>
 #include <string>
 #include <vector>
 
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index 2c00456..f59a472 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -167,15 +167,10 @@
     return false;
   }
 
-  if (!ReadProgramHeaders<EhdrType, PhdrType>(ehdr, load_bias)) {
-    return false;
-  }
-
-  // We could still potentially unwind without the section header
-  // information, so ignore any errors.
-  if (!ReadSectionHeaders<EhdrType, ShdrType>(ehdr)) {
-    log(0, "Malformed section header found, ignoring...");
-  }
+  // If we have enough information that this is an elf file, then allow
+  // malformed program and section headers.
+  ReadProgramHeaders<EhdrType, PhdrType>(ehdr, load_bias);
+  ReadSectionHeaders<EhdrType, ShdrType>(ehdr);
   return true;
 }
 
@@ -200,14 +195,12 @@
 }
 
 template <typename EhdrType, typename PhdrType>
-bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias) {
+void ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias) {
   uint64_t offset = ehdr.e_phoff;
   for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
     PhdrType phdr;
     if (!memory_->ReadFully(offset, &phdr, sizeof(phdr))) {
-      last_error_.code = ERROR_MEMORY_INVALID;
-      last_error_.address = offset;
-      return false;
+      return;
     }
 
     switch (phdr.p_type) {
@@ -242,11 +235,10 @@
       break;
     }
   }
-  return true;
 }
 
 template <typename EhdrType, typename ShdrType>
-bool ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) {
+void ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) {
   uint64_t offset = ehdr.e_shoff;
   uint64_t sec_offset = 0;
   uint64_t sec_size = 0;
@@ -267,9 +259,7 @@
   offset += ehdr.e_shentsize;
   for (size_t i = 1; i < ehdr.e_shnum; i++, offset += ehdr.e_shentsize) {
     if (!memory_->Read(offset, &shdr, sizeof(shdr))) {
-      last_error_.code = ERROR_MEMORY_INVALID;
-      last_error_.address = offset;
-      return false;
+      return;
     }
 
     if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) {
@@ -277,18 +267,14 @@
       // the string terminated names.
       ShdrType str_shdr;
       if (shdr.sh_link >= ehdr.e_shnum) {
-        last_error_.code = ERROR_UNWIND_INFO;
-        return false;
+        continue;
       }
       uint64_t str_offset = ehdr.e_shoff + shdr.sh_link * ehdr.e_shentsize;
       if (!memory_->Read(str_offset, &str_shdr, sizeof(str_shdr))) {
-        last_error_.code = ERROR_MEMORY_INVALID;
-        last_error_.address = str_offset;
-        return false;
+        continue;
       }
       if (str_shdr.sh_type != SHT_STRTAB) {
-        last_error_.code = ERROR_UNWIND_INFO;
-        return false;
+        continue;
       }
       symbols_.push_back(new Symbols(shdr.sh_offset, shdr.sh_size, shdr.sh_entsize,
                                      str_shdr.sh_offset, str_shdr.sh_size));
@@ -324,7 +310,6 @@
                                                             static_cast<uint64_t>(shdr.sh_offset)));
     }
   }
-  return true;
 }
 
 template <typename DynType>
@@ -499,11 +484,13 @@
 template bool ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>(uint64_t*);
 template bool ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>(uint64_t*);
 
-template bool ElfInterface::ReadProgramHeaders<Elf32_Ehdr, Elf32_Phdr>(const Elf32_Ehdr&, uint64_t*);
-template bool ElfInterface::ReadProgramHeaders<Elf64_Ehdr, Elf64_Phdr>(const Elf64_Ehdr&, uint64_t*);
+template void ElfInterface::ReadProgramHeaders<Elf32_Ehdr, Elf32_Phdr>(const Elf32_Ehdr&,
+                                                                       uint64_t*);
+template void ElfInterface::ReadProgramHeaders<Elf64_Ehdr, Elf64_Phdr>(const Elf64_Ehdr&,
+                                                                       uint64_t*);
 
-template bool ElfInterface::ReadSectionHeaders<Elf32_Ehdr, Elf32_Shdr>(const Elf32_Ehdr&);
-template bool ElfInterface::ReadSectionHeaders<Elf64_Ehdr, Elf64_Shdr>(const Elf64_Ehdr&);
+template void ElfInterface::ReadSectionHeaders<Elf32_Ehdr, Elf32_Shdr>(const Elf32_Ehdr&);
+template void ElfInterface::ReadSectionHeaders<Elf64_Ehdr, Elf64_Shdr>(const Elf64_Ehdr&);
 
 template bool ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(std::string*);
 template bool ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(std::string*);
diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h
index 5c1210d..a45eba8 100644
--- a/libunwindstack/include/unwindstack/ElfInterface.h
+++ b/libunwindstack/include/unwindstack/ElfInterface.h
@@ -104,10 +104,10 @@
   bool ReadAllHeaders(uint64_t* load_bias);
 
   template <typename EhdrType, typename PhdrType>
-  bool ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias);
+  void ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias);
 
   template <typename EhdrType, typename ShdrType>
-  bool ReadSectionHeaders(const EhdrType& ehdr);
+  void ReadSectionHeaders(const EhdrType& ehdr);
 
   template <typename DynType>
   bool GetSonameWithTemplate(std::string* soname);
diff --git a/libunwindstack/tests/ElfInterfaceTest.cpp b/libunwindstack/tests/ElfInterfaceTest.cpp
index aa6df84..9326bff 100644
--- a/libunwindstack/tests/ElfInterfaceTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceTest.cpp
@@ -97,9 +97,15 @@
   template <typename ElfType>
   void InitHeadersDebugFrameFail();
 
+  template <typename Ehdr, typename Phdr, typename ElfInterfaceType>
+  void InitProgramHeadersMalformed();
+
   template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
   void InitSectionHeadersMalformed();
 
+  template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
+  void InitSectionHeadersMalformedSymData();
+
   template <typename Ehdr, typename Shdr, typename Sym, typename ElfInterfaceType>
   void InitSectionHeaders(uint64_t entry_size);
 
@@ -677,6 +683,29 @@
   InitHeadersDebugFrame<ElfInterface64Fake>();
 }
 
+template <typename Ehdr, typename Phdr, typename ElfInterfaceType>
+void ElfInterfaceTest::InitProgramHeadersMalformed() {
+  std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
+
+  Ehdr ehdr = {};
+  ehdr.e_phoff = 0x100;
+  ehdr.e_phnum = 3;
+  ehdr.e_phentsize = sizeof(Phdr);
+  memory_.SetMemory(0, &ehdr, sizeof(ehdr));
+
+  uint64_t load_bias = 0;
+  ASSERT_TRUE(elf->Init(&load_bias));
+  EXPECT_EQ(0U, load_bias);
+}
+
+TEST_F(ElfInterfaceTest, init_program_headers_malformed32) {
+  InitProgramHeadersMalformed<Elf32_Ehdr, Elf32_Phdr, ElfInterface32>();
+}
+
+TEST_F(ElfInterfaceTest, init_program_headers_malformed64) {
+  InitProgramHeadersMalformed<Elf64_Ehdr, Elf64_Phdr, ElfInterface64>();
+}
+
 template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
 void ElfInterfaceTest::InitSectionHeadersMalformed() {
   std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
@@ -700,6 +729,80 @@
   InitSectionHeadersMalformed<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>();
 }
 
+template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
+void ElfInterfaceTest::InitSectionHeadersMalformedSymData() {
+  std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
+
+  uint64_t offset = 0x1000;
+
+  Ehdr ehdr = {};
+  ehdr.e_shoff = offset;
+  ehdr.e_shnum = 5;
+  ehdr.e_shentsize = sizeof(Shdr);
+  memory_.SetMemory(0, &ehdr, sizeof(ehdr));
+
+  offset += ehdr.e_shentsize;
+
+  Shdr shdr = {};
+  shdr.sh_type = SHT_SYMTAB;
+  shdr.sh_link = 4;
+  shdr.sh_addr = 0x5000;
+  shdr.sh_offset = 0x5000;
+  shdr.sh_entsize = 0x100;
+  shdr.sh_size = shdr.sh_entsize * 10;
+  memory_.SetMemory(offset, &shdr, sizeof(shdr));
+  offset += ehdr.e_shentsize;
+
+  memset(&shdr, 0, sizeof(shdr));
+  shdr.sh_type = SHT_DYNSYM;
+  shdr.sh_link = 10;
+  shdr.sh_addr = 0x6000;
+  shdr.sh_offset = 0x6000;
+  shdr.sh_entsize = 0x100;
+  shdr.sh_size = shdr.sh_entsize * 10;
+  memory_.SetMemory(offset, &shdr, sizeof(shdr));
+  offset += ehdr.e_shentsize;
+
+  memset(&shdr, 0, sizeof(shdr));
+  shdr.sh_type = SHT_DYNSYM;
+  shdr.sh_link = 2;
+  shdr.sh_addr = 0x6000;
+  shdr.sh_offset = 0x6000;
+  shdr.sh_entsize = 0x100;
+  shdr.sh_size = shdr.sh_entsize * 10;
+  memory_.SetMemory(offset, &shdr, sizeof(shdr));
+  offset += ehdr.e_shentsize;
+
+  // The string data for the entries.
+  memset(&shdr, 0, sizeof(shdr));
+  shdr.sh_type = SHT_STRTAB;
+  shdr.sh_name = 0x20000;
+  shdr.sh_offset = 0xf000;
+  shdr.sh_size = 0x1000;
+  memory_.SetMemory(offset, &shdr, sizeof(shdr));
+  offset += ehdr.e_shentsize;
+
+  uint64_t load_bias = 0;
+  ASSERT_TRUE(elf->Init(&load_bias));
+  EXPECT_EQ(0U, load_bias);
+  EXPECT_EQ(0U, elf->debug_frame_offset());
+  EXPECT_EQ(0U, elf->debug_frame_size());
+  EXPECT_EQ(0U, elf->gnu_debugdata_offset());
+  EXPECT_EQ(0U, elf->gnu_debugdata_size());
+
+  std::string name;
+  uint64_t name_offset;
+  ASSERT_FALSE(elf->GetFunctionName(0x90010, &name, &name_offset));
+}
+
+TEST_F(ElfInterfaceTest, init_section_headers_malformed_symdata32) {
+  InitSectionHeadersMalformedSymData<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>();
+}
+
+TEST_F(ElfInterfaceTest, init_section_headers_malformed_symdata64) {
+  InitSectionHeadersMalformedSymData<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>();
+}
+
 template <typename Ehdr, typename Shdr, typename Sym, typename ElfInterfaceType>
 void ElfInterfaceTest::InitSectionHeaders(uint64_t entry_size) {
   std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
@@ -708,7 +811,7 @@
 
   Ehdr ehdr = {};
   ehdr.e_shoff = offset;
-  ehdr.e_shnum = 10;
+  ehdr.e_shnum = 5;
   ehdr.e_shentsize = entry_size;
   memory_.SetMemory(0, &ehdr, sizeof(ehdr));
 
@@ -795,7 +898,7 @@
 
   Ehdr ehdr = {};
   ehdr.e_shoff = offset;
-  ehdr.e_shnum = 10;
+  ehdr.e_shnum = 6;
   ehdr.e_shentsize = sizeof(Shdr);
   ehdr.e_shstrndx = 2;
   memory_.SetMemory(0, &ehdr, sizeof(ehdr));
diff --git a/libunwindstack/tests/MapInfoGetElfTest.cpp b/libunwindstack/tests/MapInfoGetElfTest.cpp
index f599503..861b82f 100644
--- a/libunwindstack/tests/MapInfoGetElfTest.cpp
+++ b/libunwindstack/tests/MapInfoGetElfTest.cpp
@@ -319,7 +319,7 @@
   TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
   ehdr.e_shoff = 0x2000;
   ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
-  ehdr.e_shnum = 4;
+  ehdr.e_shnum = 0;
   memory_->SetMemory(0x9000, &ehdr, sizeof(ehdr));
 
   Elf* elf = info.GetElf(process_memory_, false);
@@ -341,7 +341,7 @@
   TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_X86_64);
   ehdr.e_shoff = 0x2000;
   ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
-  ehdr.e_shnum = 4;
+  ehdr.e_shnum = 0;
   memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr));
 
   Elf* elf = info.GetElf(process_memory_, false);
@@ -368,7 +368,7 @@
   TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_X86_64);
   ehdr.e_shoff = 0x2000;
   ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
-  ehdr.e_shnum = 4;
+  ehdr.e_shnum = 0;
   memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr));
 
   Elf* elf_in_threads[kNumConcurrentThreads];
diff --git a/libutils/CallStack.cpp b/libutils/CallStack.cpp
index bd6015e..2a83bd9 100644
--- a/libutils/CallStack.cpp
+++ b/libutils/CallStack.cpp
@@ -16,16 +16,15 @@
 
 #define LOG_TAG "CallStack"
 
-#include <utils/CallStack.h>
-
-#include <memory>
-
 #include <utils/Printer.h>
 #include <utils/Errors.h>
 #include <utils/Log.h>
 
 #include <backtrace/Backtrace.h>
 
+#define CALLSTACK_WEAK  // Don't generate weak definitions.
+#include <utils/CallStack.h>
+
 namespace android {
 
 CallStack::CallStack() {
@@ -76,4 +75,26 @@
     }
 }
 
+// The following four functions may be used via weak symbol references from libutils.
+// Clients assume that if any of these symbols are available, then deleteStack() is.
+
+CallStack::CallStackUPtr CallStack::getCurrentInternal(int ignoreDepth) {
+    CallStack::CallStackUPtr stack(new CallStack());
+    stack->update(ignoreDepth + 1);
+    return stack;
+}
+
+void CallStack::logStackInternal(const char* logtag, const CallStack* stack,
+                                 android_LogPriority priority) {
+    stack->log(logtag, priority);
+}
+
+String8 CallStack::stackToStringInternal(const char* prefix, const CallStack* stack) {
+    return stack->toString(prefix);
+}
+
+void CallStack::deleteStack(CallStack* stack) {
+    delete stack;
+}
+
 }; // namespace android
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
index 9074850..3f1e79a 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -17,30 +17,41 @@
 #define LOG_TAG "RefBase"
 // #define LOG_NDEBUG 0
 
+#include <memory>
+
 #include <utils/RefBase.h>
 
 #include <utils/CallStack.h>
 
+#include <utils/Mutex.h>
+
 #ifndef __unused
 #define __unused __attribute__((__unused__))
 #endif
 
-// compile with refcounting debugging enabled
-#define DEBUG_REFS                      0
+// Compile with refcounting debugging enabled.
+#define DEBUG_REFS 0
+
+// The following three are ignored unless DEBUG_REFS is set.
 
 // whether ref-tracking is enabled by default, if not, trackMe(true, false)
 // needs to be called explicitly
-#define DEBUG_REFS_ENABLED_BY_DEFAULT   0
+#define DEBUG_REFS_ENABLED_BY_DEFAULT 0
 
 // whether callstack are collected (significantly slows things down)
-#define DEBUG_REFS_CALLSTACK_ENABLED    1
+#define DEBUG_REFS_CALLSTACK_ENABLED 1
 
 // folder where stack traces are saved when DEBUG_REFS is enabled
 // this folder needs to exist and be writable
-#define DEBUG_REFS_CALLSTACK_PATH       "/data/debug"
+#define DEBUG_REFS_CALLSTACK_PATH "/data/debug"
 
 // log all reference counting operations
-#define PRINT_REFS                      0
+#define PRINT_REFS 0
+
+// Continue after logging a stack trace if ~RefBase discovers that reference
+// count has never been incremented. Normally we conspicuously crash in that
+// case.
+#define DEBUG_REFBASE_DESTRUCTION 1
 
 // ---------------------------------------------------------------------------
 
@@ -184,7 +195,7 @@
                 char inc = refs->ref >= 0 ? '+' : '-';
                 ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
 #if DEBUG_REFS_CALLSTACK_ENABLED
-                refs->stack.log(LOG_TAG);
+                CallStack::logStack(LOG_TAG, refs->stack.get());
 #endif
                 refs = refs->next;
             }
@@ -198,14 +209,14 @@
                 char inc = refs->ref >= 0 ? '+' : '-';
                 ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
 #if DEBUG_REFS_CALLSTACK_ENABLED
-                refs->stack.log(LOG_TAG);
+                CallStack::logStack(LOG_TAG, refs->stack.get());
 #endif
                 refs = refs->next;
             }
         }
         if (dumpStack) {
             ALOGE("above errors at:");
-            CallStack stack(LOG_TAG);
+            CallStack::logStack(LOG_TAG);
         }
     }
 
@@ -279,7 +290,7 @@
                      this);
             int rc = open(name, O_RDWR | O_CREAT | O_APPEND, 644);
             if (rc >= 0) {
-                write(rc, text.string(), text.length());
+                (void)write(rc, text.string(), text.length());
                 close(rc);
                 ALOGD("STACK TRACE for %p saved in %s", this, name);
             }
@@ -294,7 +305,7 @@
         ref_entry* next;
         const void* id;
 #if DEBUG_REFS_CALLSTACK_ENABLED
-        CallStack stack;
+        CallStack::CallStackUPtr stack;
 #endif
         int32_t ref;
     };
@@ -311,7 +322,7 @@
             ref->ref = mRef;
             ref->id = id;
 #if DEBUG_REFS_CALLSTACK_ENABLED
-            ref->stack.update(2);
+            ref->stack = CallStack::getCurrent(2);
 #endif
             ref->next = *refs;
             *refs = ref;
@@ -346,7 +357,7 @@
                 ref = ref->next;
             }
 
-            CallStack stack(LOG_TAG);
+            CallStack::logStack(LOG_TAG);
         }
     }
 
@@ -373,7 +384,7 @@
                      inc, refs->id, refs->ref);
             out->append(buf);
 #if DEBUG_REFS_CALLSTACK_ENABLED
-            out->append(refs->stack.toString("\t\t"));
+            out->append(CallStack::stackToString("\t\t", refs->stack.get()));
 #else
             out->append("\t\t(call stacks disabled)");
 #endif
@@ -700,16 +711,16 @@
         if (mRefs->mWeak.load(std::memory_order_relaxed) == 0) {
             delete mRefs;
         }
-    } else if (mRefs->mStrong.load(std::memory_order_relaxed)
-            == INITIAL_STRONG_VALUE) {
+    } else if (mRefs->mStrong.load(std::memory_order_relaxed) == INITIAL_STRONG_VALUE) {
         // We never acquired a strong reference on this object.
-        LOG_ALWAYS_FATAL_IF(mRefs->mWeak.load() != 0,
-                "RefBase: Explicit destruction with non-zero weak "
-                "reference count");
-        // TODO: Always report if we get here. Currently MediaMetadataRetriever
-        // C++ objects are inconsistently managed and sometimes get here.
-        // There may be other cases, but we believe they should all be fixed.
-        delete mRefs;
+#if DEBUG_REFBASE_DESTRUCTION
+        // Treating this as fatal is prone to causing boot loops. For debugging, it's
+        // better to treat as non-fatal.
+        ALOGD("RefBase: Explicit destruction, weak count = %d (in %p)", mRefs->mWeak.load(), this);
+        CallStack::logStack(LOG_TAG);
+#else
+        LOG_ALWAYS_FATAL("RefBase: Explicit destruction, weak count = %d", mRefs->mWeak.load());
+#endif
     }
     // For debugging purposes, clear mRefs.  Ineffective against outstanding wp's.
     const_cast<weakref_impl*&>(mRefs) = nullptr;
diff --git a/libutils/include/utils/CallStack.h b/libutils/include/utils/CallStack.h
index 0c1b875..a7b1d10 100644
--- a/libutils/include/utils/CallStack.h
+++ b/libutils/include/utils/CallStack.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_CALLSTACK_H
 #define ANDROID_CALLSTACK_H
 
+#include <memory>
+
 #include <android/log.h>
 #include <backtrace/backtrace_constants.h>
 #include <utils/String8.h>
@@ -25,6 +27,11 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#ifndef CALLSTACK_WEAK
+#define CALLSTACK_WEAK __attribute__((weak))
+#endif
+#define ALWAYS_INLINE __attribute__((always_inline))
+
 namespace android {
 
 class Printer;
@@ -36,7 +43,7 @@
     CallStack();
     // Create a callstack with the current thread's stack trace.
     // Immediately dump it to logcat using the given logtag.
-    CallStack(const char* logtag, int32_t ignoreDepth=1);
+    CallStack(const char* logtag, int32_t ignoreDepth = 1);
     ~CallStack();
 
     // Reset the stack frames (same as creating an empty call stack).
@@ -44,7 +51,7 @@
 
     // Immediately collect the stack traces for the specified thread.
     // The default is to dump the stack of the current call.
-    void update(int32_t ignoreDepth=1, pid_t tid=BACKTRACE_CURRENT_THREAD);
+    void update(int32_t ignoreDepth = 1, pid_t tid = BACKTRACE_CURRENT_THREAD);
 
     // Dump a stack trace to the log using the supplied logtag.
     void log(const char* logtag,
@@ -63,7 +70,58 @@
     // Get the count of stack frames that are in this call stack.
     size_t size() const { return mFrameLines.size(); }
 
-private:
+    // DO NOT USE ANYTHING BELOW HERE. The following public members are expected
+    // to disappear again shortly, once a better replacement facility exists.
+    // The replacement facility will be incompatible!
+
+    // Debugging accesses to some basic functionality. These use weak symbols to
+    // avoid introducing a dependency on libutilscallstack. Such a dependency from
+    // libutils results in a cyclic build dependency. These routines can be called
+    // from within libutils. But if the actual library is unavailable, they do
+    // nothing.
+    //
+    // DO NOT USE THESE. They will disappear.
+    struct StackDeleter {
+        void operator()(CallStack* stack) { deleteStack(stack); }
+    };
+
+    typedef std::unique_ptr<CallStack, StackDeleter> CallStackUPtr;
+
+    // Return current call stack if possible, nullptr otherwise.
+    static CallStackUPtr ALWAYS_INLINE getCurrent(int32_t ignoreDepth = 1) {
+        if (reinterpret_cast<uintptr_t>(getCurrentInternal) == 0) {
+            ALOGW("CallStack::getCurrentInternal not linked, returning null");
+            return CallStackUPtr(nullptr);
+        } else {
+            return getCurrentInternal(ignoreDepth);
+        }
+    }
+    static void ALWAYS_INLINE logStack(const char* logtag, CallStack* stack = getCurrent().get(),
+                                       android_LogPriority priority = ANDROID_LOG_DEBUG) {
+        if (reinterpret_cast<uintptr_t>(logStackInternal) != 0 && stack != nullptr) {
+            logStackInternal(logtag, stack, priority);
+        } else {
+            ALOGW("CallStack::logStackInternal not linked");
+        }
+    }
+    static String8 ALWAYS_INLINE stackToString(const char* prefix = nullptr,
+                                               const CallStack* stack = getCurrent().get()) {
+        if (reinterpret_cast<uintptr_t>(stackToStringInternal) != 0 && stack != nullptr) {
+            return stackToStringInternal(prefix, stack);
+        } else {
+            return String8("<CallStack package not linked>");
+        }
+    }
+
+  private:
+    static CallStackUPtr CALLSTACK_WEAK getCurrentInternal(int32_t ignoreDepth);
+    static void CALLSTACK_WEAK logStackInternal(const char* logtag, const CallStack* stack,
+                                                android_LogPriority priority);
+    static String8 CALLSTACK_WEAK stackToStringInternal(const char* prefix, const CallStack* stack);
+    // The deleter is only invoked on non-null pointers. Hence it will never be
+    // invoked if CallStack is not linked.
+    static void CALLSTACK_WEAK deleteStack(CallStack* stack);
+
     Vector<String8> mFrameLines;
 };