StreamHal: Add power logging
Test: adb shell dumpsys media.audio_flinger
Bug: 62307033
Bug: 62381511
Change-Id: Ie15863f3c207e5651ce0b8818b9e38737bad77d8
diff --git a/media/libaudiohal/Android.mk b/media/libaudiohal/Android.mk
index e592169..827908e 100644
--- a/media/libaudiohal/Android.mk
+++ b/media/libaudiohal/Android.mk
@@ -3,6 +3,7 @@
include $(CLEAR_VARS)
LOCAL_SHARED_LIBRARIES := \
+ libaudioutils \
libcutils \
liblog \
libutils \
diff --git a/media/libaudiohal/StreamHalHidl.cpp b/media/libaudiohal/StreamHalHidl.cpp
index 42785d5..176abee 100644
--- a/media/libaudiohal/StreamHalHidl.cpp
+++ b/media/libaudiohal/StreamHalHidl.cpp
@@ -48,6 +48,18 @@
: ConversionHelperHidl("Stream"),
mStream(stream),
mHalThreadPriority(HAL_THREAD_PRIORITY_DEFAULT) {
+
+ // Instrument audio signal power logging.
+ // Note: This assumes channel mask, format, and sample rate do not change after creation.
+ if (mStream != nullptr && mStreamPowerLog.isUserDebugOrEngBuild()) {
+ // Obtain audio properties (see StreamHalHidl::getAudioProperties() below).
+ Return<void> ret = mStream->getAudioProperties(
+ [&](uint32_t sr, AudioChannelMask m, AudioFormat f) {
+ mStreamPowerLog.init(sr,
+ static_cast<audio_channel_mask_t>(m),
+ static_cast<audio_format_t>(f));
+ });
+ }
}
StreamHalHidl::~StreamHalHidl() {
@@ -135,6 +147,7 @@
hidlHandle->data[0] = fd;
Return<void> ret = mStream->debugDump(hidlHandle);
native_handle_delete(hidlHandle);
+ mStreamPowerLog.dump(fd);
return processReturn("dump", ret);
}
@@ -311,7 +324,7 @@
return status;
}
- return callWriterThread(
+ status = callWriterThread(
WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
[&] (const WriteStatus& writeStatus) {
*written = writeStatus.reply.written;
@@ -320,6 +333,8 @@
"hal reports more bytes written than asked for: %lld > %lld",
(long long)*written, (long long)bytes);
});
+ mStreamPowerLog.log(buffer, *written);
+ return status;
}
status_t StreamOutHalHidl::callWriterThread(
@@ -580,7 +595,7 @@
ReadParameters params;
params.command = ReadCommand::READ;
params.params.read = bytes;
- return callReaderThread(params, "read",
+ status = callReaderThread(params, "read",
[&](const ReadStatus& readStatus) {
const size_t availToRead = mDataMQ->availableToRead();
if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
@@ -591,6 +606,8 @@
(int32_t)availToRead, (int32_t)readStatus.reply.read);
*read = readStatus.reply.read;
});
+ mStreamPowerLog.log(buffer, *read);
+ return status;
}
status_t StreamInHalHidl::callReaderThread(
diff --git a/media/libaudiohal/StreamHalHidl.h b/media/libaudiohal/StreamHalHidl.h
index a7df276..a69cce8 100644
--- a/media/libaudiohal/StreamHalHidl.h
+++ b/media/libaudiohal/StreamHalHidl.h
@@ -27,6 +27,7 @@
#include <media/audiohal/StreamHalInterface.h>
#include "ConversionHelperHidl.h"
+#include "StreamPowerLog.h"
using ::android::hardware::audio::V2_0::IStream;
using ::android::hardware::audio::V2_0::IStreamIn;
@@ -103,6 +104,9 @@
bool requestHalThreadPriority(pid_t threadPid, pid_t threadId);
+ // mStreamPowerLog is used for audio signal power logging.
+ StreamPowerLog mStreamPowerLog;
+
private:
const int HAL_THREAD_PRIORITY_DEFAULT = -1;
IStream *mStream;
diff --git a/media/libaudiohal/StreamHalLocal.cpp b/media/libaudiohal/StreamHalLocal.cpp
index 05800a0..dc17f5c 100644
--- a/media/libaudiohal/StreamHalLocal.cpp
+++ b/media/libaudiohal/StreamHalLocal.cpp
@@ -27,7 +27,15 @@
namespace android {
StreamHalLocal::StreamHalLocal(audio_stream_t *stream, sp<DeviceHalLocal> device)
- : mDevice(device), mStream(stream) {
+ : mDevice(device),
+ mStream(stream) {
+ // Instrument audio signal power logging.
+ // Note: This assumes channel mask, format, and sample rate do not change after creation.
+ if (mStream != nullptr && mStreamPowerLog.isUserDebugOrEngBuild()) {
+ mStreamPowerLog.init(mStream->get_sample_rate(mStream),
+ mStream->get_channels(mStream),
+ mStream->get_format(mStream));
+ }
}
StreamHalLocal::~StreamHalLocal() {
@@ -95,7 +103,9 @@
}
status_t StreamHalLocal::dump(int fd) {
- return mStream->dump(mStream, fd);
+ status_t status = mStream->dump(mStream, fd);
+ mStreamPowerLog.dump(fd);
+ return status;
}
status_t StreamHalLocal::setHalThreadPriority(int) {
@@ -133,6 +143,7 @@
ssize_t writeResult = mStream->write(mStream, buffer, bytes);
if (writeResult > 0) {
*written = writeResult;
+ mStreamPowerLog.log(buffer, *written);
return OK;
} else {
*written = 0;
@@ -266,6 +277,7 @@
ssize_t readResult = mStream->read(mStream, buffer, bytes);
if (readResult > 0) {
*read = readResult;
+ mStreamPowerLog.log( buffer, *read);
return OK;
} else {
*read = 0;
diff --git a/media/libaudiohal/StreamHalLocal.h b/media/libaudiohal/StreamHalLocal.h
index 8c96c1f..c7136df 100644
--- a/media/libaudiohal/StreamHalLocal.h
+++ b/media/libaudiohal/StreamHalLocal.h
@@ -18,6 +18,7 @@
#define ANDROID_HARDWARE_STREAM_HAL_LOCAL_H
#include <media/audiohal/StreamHalInterface.h>
+#include "StreamPowerLog.h"
namespace android {
@@ -83,6 +84,9 @@
sp<DeviceHalLocal> mDevice;
+ // mStreamPowerLog is used for audio signal power logging.
+ StreamPowerLog mStreamPowerLog;
+
private:
audio_stream_t *mStream;
};
diff --git a/media/libaudiohal/StreamPowerLog.h b/media/libaudiohal/StreamPowerLog.h
new file mode 100644
index 0000000..a78b1aa
--- /dev/null
+++ b/media/libaudiohal/StreamPowerLog.h
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_STREAM_POWER_LOG_H
+#define ANDROID_HARDWARE_STREAM_POWER_LOG_H
+
+#include <audio_utils/clock.h>
+#include <audio_utils/PowerLog.h>
+#include <cutils/properties.h>
+#include <system/audio.h>
+
+namespace android {
+
+class StreamPowerLog {
+public:
+ StreamPowerLog() :
+ mIsUserDebugOrEngBuild(is_userdebug_or_eng_build()),
+ mPowerLog(nullptr),
+ mFrameSize(0) {
+ // use init() to set up the power log.
+ }
+
+ ~StreamPowerLog() {
+ power_log_destroy(mPowerLog); // OK for null mPowerLog
+ mPowerLog = nullptr;
+ }
+
+ // A one-time initialization (do not call twice) before using StreamPowerLog.
+ void init(uint32_t sampleRate, audio_channel_mask_t channelMask, audio_format_t format) {
+ if (mPowerLog == nullptr) {
+ // Note: A way to get channel count for both input and output channel masks
+ // but does not check validity of the channel mask.
+ const uint32_t channelCount = popcount(audio_channel_mask_get_bits(channelMask));
+ mFrameSize = channelCount * audio_bytes_per_sample(format);
+ if (mFrameSize > 0) {
+ const size_t kPowerLogFramesPerEntry =
+ (long long)sampleRate * kPowerLogSamplingIntervalMs / 1000;
+ mPowerLog = power_log_create(
+ sampleRate,
+ channelCount,
+ format,
+ kPowerLogEntries,
+ kPowerLogFramesPerEntry);
+ }
+ }
+ // mPowerLog may be NULL (not the right build, format not accepted, etc.).
+ }
+
+ // Dump the power log to fd.
+ void dump(int fd) const {
+ // OK for null mPowerLog
+ (void)power_log_dump(
+ mPowerLog, fd, " " /* prefix */, kPowerLogLines, 0 /* limit_ns */);
+ }
+
+ // Log the audio data contained in buffer.
+ void log(const void *buffer, size_t sizeInBytes) const {
+ if (mPowerLog != nullptr) { // mFrameSize is always nonzero if mPowerLog exists.
+ power_log_log(
+ mPowerLog, buffer, sizeInBytes / mFrameSize, audio_utils_get_real_time_ns());
+ }
+ }
+
+ bool isUserDebugOrEngBuild() const {
+ return mIsUserDebugOrEngBuild;
+ }
+
+private:
+
+ static inline bool is_userdebug_or_eng_build() {
+ char value[PROPERTY_VALUE_MAX];
+ (void)property_get("ro.build.type", value, "unknown"); // ignore actual length
+ return strcmp(value, "userdebug") == 0 || strcmp(value, "eng") == 0;
+ }
+
+ // Audio signal power log configuration.
+ static const size_t kPowerLogLines = 40;
+ static const size_t kPowerLogSamplingIntervalMs = 50;
+ static const size_t kPowerLogEntries = (1 /* minutes */ * 60 /* seconds */ * 1000 /* msec */
+ / kPowerLogSamplingIntervalMs);
+
+ const bool mIsUserDebugOrEngBuild;
+ power_log_t *mPowerLog;
+ size_t mFrameSize;
+};
+
+} // namespace android
+
+#endif // ANDROID_HARDWARE_STREAM_POWER_LOG_H