AudioFlinger: Move NBLog thread_local to no linkage.
Access the thread_local by getter/setter only.
This prevents a memory leak with the clang compiler.
Test: adb shell dumpsys media.audio_flinger --unreachable
Bug: 284657986
Merged-In: Ic7128eea2aef47289c6e38ebca6fb5292d919410
Change-Id: Ic7128eea2aef47289c6e38ebca6fb5292d919410
(cherry picked from commit 5a5b514ac4673a82f665ebc230174a6a4a802632)
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 20f9470..654f506 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -3833,7 +3833,7 @@
bool AudioFlinger::PlaybackThread::threadLoop()
NO_THREAD_SAFETY_ANALYSIS // manual locking of AudioFlinger
{
- tlNBLogWriter = mNBLogWriter.get();
+ aflog::setThreadWriter(mNBLogWriter.get());
Vector< sp<Track> > tracksToRemove;
diff --git a/services/audioflinger/afutils/TypedLogger.cpp b/services/audioflinger/afutils/TypedLogger.cpp
index 57c206b..7c546a5 100644
--- a/services/audioflinger/afutils/TypedLogger.cpp
+++ b/services/audioflinger/afutils/TypedLogger.cpp
@@ -22,6 +22,25 @@
#include <pthread.h>
#include "TypedLogger.h"
-namespace android {
+namespace android::aflog {
+
+// External linkage access of thread local storage outside of this shared library
+// causes orphaned memory allocations. This occurs in the implementation of
+// __emutls_get_address(), see b/284657986.
+//
+// We only expose a thread local storage getter and setter here, not the
+// actual thread local variable.
+
+namespace {
thread_local NBLog::Writer *tlNBLogWriter;
+} // namespace
+
+NBLog::Writer *getThreadWriter() {
+ return tlNBLogWriter;
}
+
+void setThreadWriter(NBLog::Writer *writer) {
+ tlNBLogWriter = writer;
+}
+
+} // namespace android::aflog
diff --git a/services/audioflinger/afutils/TypedLogger.h b/services/audioflinger/afutils/TypedLogger.h
index feb71e3..f34a50c 100644
--- a/services/audioflinger/afutils/TypedLogger.h
+++ b/services/audioflinger/afutils/TypedLogger.h
@@ -85,56 +85,57 @@
// slower than nullptr check when logging is enabled at compile-time and disabled at runtime.
// Write formatted entry to log
-#define LOGT(fmt, ...) do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
+#define LOGT(fmt, ...) do { NBLog::Writer *x = aflog::getThreadWriter(); if (x != nullptr) \
x->logFormat((fmt), hash(__FILE__, __LINE__), ##__VA_ARGS__); } \
while (0)
// Write histogram timestamp entry
-#define LOG_HIST_TS() do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
+#define LOG_HIST_TS() do { NBLog::Writer *x = aflog::getThreadWriter(); if (x != nullptr) \
x->logEventHistTs(NBLog::EVENT_HISTOGRAM_ENTRY_TS, hash(__FILE__, __LINE__)); } while(0)
// Record that audio was turned on/off
-#define LOG_AUDIO_STATE() do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
+#define LOG_AUDIO_STATE() do { NBLog::Writer *x = aflog::getThreadWriter(); if (x != nullptr) \
x->logEventHistTs(NBLog::EVENT_AUDIO_STATE, hash(__FILE__, __LINE__)); } while(0)
// Log the difference bewteen frames presented by HAL and frames written to HAL output sink,
// divided by the sample rate. Parameter ms is of type double.
-#define LOG_LATENCY(ms) do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
+#define LOG_LATENCY(ms) do { NBLog::Writer *x = aflog::getThreadWriter(); if (x != nullptr) \
x->log<NBLog::EVENT_LATENCY>(ms); } while (0)
// Record thread overrun event nanosecond timestamp. Parameter ns is an int64_t.
-#define LOG_OVERRUN(ns) do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
+#define LOG_OVERRUN(ns) do { NBLog::Writer *x = aflog::getThreadWriter(); if (x != nullptr) \
x->log<NBLog::EVENT_OVERRUN>(ns); } while (0)
// Record thread info. This currently includes type, frameCount, and sampleRate.
// Parameter type is thread_info_t as defined in NBLog.h.
-#define LOG_THREAD_INFO(info) do { NBLog::Writer *x = tlNBLogWriter; \
+#define LOG_THREAD_INFO(info) do { NBLog::Writer *x = aflog::getThreadWriter(); \
if (x != nullptr) x->log<NBLog::EVENT_THREAD_INFO>(info); } while (0)
-#define LOG_THREAD_PARAMS(params) do {NBLog::Writer *x = tlNBLogWriter; \
+#define LOG_THREAD_PARAMS(params) do {NBLog::Writer *x = aflog::getThreadWriter(); \
if (x != nullptr) x->log<NBLog::EVENT_THREAD_PARAMS>(params); } while (0)
// Record thread underrun event nanosecond timestamp. Parameter ns is an int64_t.
-#define LOG_UNDERRUN(ns) do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
+#define LOG_UNDERRUN(ns) do { NBLog::Writer *x = aflog::getThreadWriter(); if (x != nullptr) \
x->log<NBLog::EVENT_UNDERRUN>(ns); } while (0)
// Record thread warmup time in milliseconds. Parameter ms is of type double.
-#define LOG_WARMUP_TIME(ms) do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
+#define LOG_WARMUP_TIME(ms) do { \
+ NBLog::Writer *x = aflog::getThreadWriter(); if (x != nullptr) \
x->log<NBLog::EVENT_WARMUP_TIME>(ms); } while (0)
// Record a typed entry that represents a thread's work time in nanoseconds.
// Parameter ns should be of type uint32_t.
-#define LOG_WORK_TIME(ns) do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
+#define LOG_WORK_TIME(ns) do { NBLog::Writer *x = aflog::getThreadWriter(); if (x != nullptr) \
x->log<NBLog::EVENT_WORK_TIME>(ns); } while (0)
-namespace android {
-extern "C" {
+namespace android::aflog {
// TODO consider adding a thread_local NBLog::Writer tlStubNBLogWriter and then
-// initialize below tlNBLogWriter to &tlStubNBLogWriter to remove the need to
+// initialize setThreadWriter() to &tlStubNBLogWriter to remove the need to
// check for nullptr every time. Also reduces the need to add a new logging macro above
// each time we want to log a new type.
-extern thread_local NBLog::Writer *tlNBLogWriter;
-}
-} // namespace android
+
+NBLog::Writer *getThreadWriter();
+void setThreadWriter(NBLog::Writer *writer);
+} // namespace android::aflog
#endif // ANDROID_TYPED_LOGGER_H
diff --git a/services/audioflinger/fastpath/FastThread.cpp b/services/audioflinger/fastpath/FastThread.cpp
index 77071dc..2ebdbc1 100644
--- a/services/audioflinger/fastpath/FastThread.cpp
+++ b/services/audioflinger/fastpath/FastThread.cpp
@@ -88,7 +88,7 @@
{
// LOGT now works even if tlNBLogWriter is nullptr, but we're considering changing that,
// so this initialization permits a future change to remove the check for nullptr.
- tlNBLogWriter = mDummyNBLogWriter.get();
+ aflog::setThreadWriter(mDummyNBLogWriter.get());
for (;;) {
// either nanosleep, sched_yield, or busy wait
@@ -118,9 +118,10 @@
// As soon as possible of learning of a new dump area, start using it
mDumpState = next->mDumpState != nullptr ? next->mDumpState : mDummyDumpState;
- tlNBLogWriter = next->mNBLogWriter != nullptr ?
+ NBLog::Writer * const writer = next->mNBLogWriter != nullptr ?
next->mNBLogWriter : mDummyNBLogWriter.get();
- setNBLogWriter(tlNBLogWriter); // This is used for debugging only
+ aflog::setThreadWriter(writer);
+ setNBLogWriter(writer); // This is used for debugging only
// We want to always have a valid reference to the previous (non-idle) state.
// However, the state queue only guarantees access to current and previous states.