Merge "TextDescription: Fix to parse ftab box" into rvc-dev
diff --git a/drm/drmserver/Android.bp b/drm/drmserver/Android.bp
index f427834..b68e6c2 100644
--- a/drm/drmserver/Android.bp
+++ b/drm/drmserver/Android.bp
@@ -24,8 +24,8 @@
],
shared_libs: [
- "libmedia",
"libmediametrics",
+ "libmediautils",
"libcutils",
"libutils",
"liblog",
diff --git a/drm/drmserver/DrmManagerService.cpp b/drm/drmserver/DrmManagerService.cpp
index 4b8b3f6..c830c6e 100644
--- a/drm/drmserver/DrmManagerService.cpp
+++ b/drm/drmserver/DrmManagerService.cpp
@@ -19,7 +19,7 @@
#include <utils/Log.h>
#include <private/android_filesystem_config.h>
-#include <media/MemoryLeakTrackUtil.h>
+#include <mediautils/MemoryLeakTrackUtil.h>
#include <errno.h>
#include <utils/threads.h>
diff --git a/media/codec2/components/avc/C2SoftAvcDec.cpp b/media/codec2/components/avc/C2SoftAvcDec.cpp
index 56813c4..d686eb1 100644
--- a/media/codec2/components/avc/C2SoftAvcDec.cpp
+++ b/media/codec2/components/avc/C2SoftAvcDec.cpp
@@ -35,6 +35,7 @@
constexpr char COMPONENT_NAME[] = "c2.android.avc.decoder";
constexpr uint32_t kDefaultOutputDelay = 8;
constexpr uint32_t kMaxOutputDelay = 16;
+constexpr uint32_t kMinInputBytes = 4;
} // namespace
class C2SoftAvcDec::IntfImpl : public SimpleInterface<void>::BaseParams {
@@ -817,7 +818,7 @@
inSize, (int)work->input.ordinal.timestamp.peeku(),
(int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
size_t inPos = 0;
- while (inPos < inSize) {
+ while (inPos < inSize && inSize - inPos >= kMinInputBytes) {
if (C2_OK != ensureDecoderState(pool)) {
mSignalledError = true;
work->workletsProcessed = 1u;
@@ -904,7 +905,6 @@
work->result = C2_CORRUPTED;
return;
}
- continue;
}
if (0 < s_decode_op.u4_pic_wd && 0 < s_decode_op.u4_pic_ht) {
if (mHeaderDecoded == false) {
@@ -937,16 +937,7 @@
if (s_decode_op.u4_output_present) {
finishWork(s_decode_op.u4_ts, work);
}
- if (0 == s_decode_op.u4_num_bytes_consumed) {
- ALOGD("Bytes consumed is zero. Ignoring remaining bytes");
- break;
- }
inPos += s_decode_op.u4_num_bytes_consumed;
- if (hasPicture && (inSize - inPos)) {
- ALOGD("decoded frame in current access nal, ignoring further trailing bytes %d",
- (int)inSize - (int)inPos);
- break;
- }
}
if (eos) {
drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index b72a8cc..aea28c0 100755
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -2896,7 +2896,7 @@
return ERROR_MALFORMED;
}
- parseID3v2MetaData(data_offset + 6);
+ parseID3v2MetaData(data_offset + 6, chunk_data_size - 6);
break;
}
@@ -4167,8 +4167,19 @@
return OK;
}
-void MPEG4Extractor::parseID3v2MetaData(off64_t offset) {
- ID3 id3(mDataSource, true /* ignorev1 */, offset);
+void MPEG4Extractor::parseID3v2MetaData(off64_t offset, uint64_t size) {
+ uint8_t *buffer = new (std::nothrow) uint8_t[size];
+ if (buffer == NULL) {
+ return;
+ }
+ if (mDataSource->readAt(offset, buffer, size) != (ssize_t)size) {
+ delete[] buffer;
+ buffer = NULL;
+ return;
+ }
+
+ ID3 id3(buffer, size, true /* ignorev1 */);
+ delete[] buffer;
if (id3.isValid()) {
struct Map {
diff --git a/media/extractors/mp4/MPEG4Extractor.h b/media/extractors/mp4/MPEG4Extractor.h
index 3af432d..1e49d50 100644
--- a/media/extractors/mp4/MPEG4Extractor.h
+++ b/media/extractors/mp4/MPEG4Extractor.h
@@ -161,7 +161,7 @@
status_t parseITunesMetaData(off64_t offset, size_t size);
status_t parseColorInfo(off64_t offset, size_t size);
status_t parse3GPPMetaData(off64_t offset, size_t size, int depth);
- void parseID3v2MetaData(off64_t offset);
+ void parseID3v2MetaData(off64_t offset, uint64_t size);
status_t parseQTMetaKey(off64_t data_offset, size_t data_size);
status_t parseQTMetaVal(int32_t keyId, off64_t data_offset, size_t data_size);
diff --git a/media/libmediametrics/include/media/MediaMetricsItem.h b/media/libmediametrics/include/media/MediaMetricsItem.h
index 08720f1..591e714 100644
--- a/media/libmediametrics/include/media/MediaMetricsItem.h
+++ b/media/libmediametrics/include/media/MediaMetricsItem.h
@@ -208,11 +208,11 @@
template<size_t N>
static inline bool startsWith(const std::string &s, const char (&comp)[N]) {
- return !strncmp(s.c_str(), comp, N - 1);
+ return !strncmp(s.c_str(), comp, N - 1); // last char is null termination
}
static inline bool startsWith(const std::string& s, const std::string& comp) {
- return !strncmp(s.c_str(), comp.c_str(), comp.size() - 1);
+ return !strncmp(s.c_str(), comp.c_str(), comp.size());
}
/**
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 81ffcbc..42a0622 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -57,7 +57,6 @@
#include <media/MediaMetadataRetrieverInterface.h>
#include <media/Metadata.h>
#include <media/AudioTrack.h>
-#include <media/MemoryLeakTrackUtil.h>
#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/MediaCodecConstants.h>
#include <media/stagefright/MediaCodecList.h>
@@ -68,7 +67,7 @@
#include <media/stagefright/foundation/ALooperRoster.h>
#include <media/stagefright/SurfaceUtils.h>
#include <mediautils/BatteryNotifier.h>
-
+#include <mediautils/MemoryLeakTrackUtil.h>
#include <memunreachable/memunreachable.h>
#include <system/audio.h>
diff --git a/media/utils/MemoryLeakTrackUtil.cpp b/media/utils/MemoryLeakTrackUtil.cpp
index 6166859..fdb8c4f 100644
--- a/media/utils/MemoryLeakTrackUtil.cpp
+++ b/media/utils/MemoryLeakTrackUtil.cpp
@@ -19,7 +19,7 @@
#define LOG_TAG "MemoryLeackTrackUtil"
#include <utils/Log.h>
-#include "media/MemoryLeakTrackUtil.h"
+#include <mediautils/MemoryLeakTrackUtil.h>
#include <sstream>
#include <bionic/malloc.h>
diff --git a/media/libmedia/include/media/MemoryLeakTrackUtil.h b/media/utils/include/mediautils/MemoryLeakTrackUtil.h
similarity index 100%
rename from media/libmedia/include/media/MemoryLeakTrackUtil.h
rename to media/utils/include/mediautils/MemoryLeakTrackUtil.h
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 1be2fcb..5c891e2 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -67,10 +67,10 @@
#include <powermanager/PowerManager.h>
#include <media/IMediaLogService.h>
-#include <media/MemoryLeakTrackUtil.h>
#include <media/nbaio/Pipe.h>
#include <media/nbaio/PipeReader.h>
#include <mediautils/BatteryNotifier.h>
+#include <mediautils/MemoryLeakTrackUtil.h>
#include <mediautils/ServiceUtilities.h>
#include <mediautils/TimeCheck.h>
#include <private/android_filesystem_config.h>
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h b/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h
index 6e29632..1596ff7 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h
@@ -41,11 +41,24 @@
IoDescriptor& desc, Filter filter, bool& active, const DeviceVector& devices)
{
auto activeClients = desc->clientsList(true /*activeOnly*/);
- auto activeClientsWithRoute =
- desc->clientsList(true /*activeOnly*/, filter, true /*preferredDevice*/);
active = activeClients.size() > 0;
- if (active && activeClients.size() == activeClientsWithRoute.size()) {
- return devices.getDeviceFromId(activeClientsWithRoute[0]->preferredDeviceId());
+
+ if (active) {
+ // On MMAP IOs, the preferred device is selected by the first client (virtual client
+ // created when the mmap stream is opened). This client is never active.
+ // On non MMAP IOs, the preferred device is honored only if all active clients have
+ // a preferred device in which case the first client drives the selection.
+ if (desc->getPolicyAudioPort()->isMmap()) {
+ // The client list is never empty on a MMAP IO
+ return devices.getDeviceFromId(
+ desc->clientsList(false /*activeOnly*/)[0]->preferredDeviceId());
+ } else {
+ auto activeClientsWithRoute =
+ desc->clientsList(true /*activeOnly*/, filter, true /*preferredDevice*/);
+ if (activeClients.size() == activeClientsWithRoute.size()) {
+ return devices.getDeviceFromId(activeClientsWithRoute[0]->preferredDeviceId());
+ }
+ }
}
return nullptr;
}
diff --git a/services/audiopolicy/common/managerdefinitions/include/PolicyAudioPort.h b/services/audiopolicy/common/managerdefinitions/include/PolicyAudioPort.h
index 99df3c0..d2f6297 100644
--- a/services/audiopolicy/common/managerdefinitions/include/PolicyAudioPort.h
+++ b/services/audiopolicy/common/managerdefinitions/include/PolicyAudioPort.h
@@ -107,6 +107,15 @@
(mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD));
}
+ inline bool isMmap() const
+ {
+ return (asAudioPort()->getType() == AUDIO_PORT_TYPE_MIX)
+ && (((asAudioPort()->getRole() == AUDIO_PORT_ROLE_SOURCE) &&
+ ((mFlags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) != 0))
+ || ((asAudioPort()->getRole() == AUDIO_PORT_ROLE_SINK) &&
+ ((mFlags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0)));
+ }
+
void addRoute(const sp<AudioRoute> &route) { mRoutes.add(route); }
const AudioRouteVector &getRoutes() const { return mRoutes; }
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index bdd2427..5aa6271 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -2405,9 +2405,7 @@
for (size_t i = 0; i < mInputs.size(); i++) {
const sp<AudioInputDescriptor> input = mInputs.valueAt(i);
if (input->clientsList().size() == 0
- || !mAvailableInputDevices.containsAtLeastOne(input->supportedDevices())
- || (input->getPolicyAudioPort()->getFlags()
- & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0) {
+ || !mAvailableInputDevices.containsAtLeastOne(input->supportedDevices())) {
inputsToClose.push_back(mInputs.keyAt(i));
} else {
bool close = false;
diff --git a/services/audiopolicy/service/CaptureStateNotifier.cpp b/services/audiopolicy/service/CaptureStateNotifier.cpp
index 8a18efa..135e0a2 100644
--- a/services/audiopolicy/service/CaptureStateNotifier.cpp
+++ b/services/audiopolicy/service/CaptureStateNotifier.cpp
@@ -1,7 +1,7 @@
-#include "CaptureStateNotifier.h"
-
#define LOG_TAG "CaptureStateNotifier"
+#include "CaptureStateNotifier.h"
+
#include <android/media/ICaptureStateListener.h>
#include <binder/IBinder.h>
#include <utils/Log.h>
@@ -22,9 +22,9 @@
CaptureStateNotifier* const mNotifier;
};
-CaptureStateNotifier::CaptureStateNotifier(bool initialActive) {
- mActive = initialActive;
-}
+CaptureStateNotifier::CaptureStateNotifier(bool initialActive)
+ : mDeathRecipient(new DeathRecipient(this)), mActive(
+ initialActive) {}
CaptureStateNotifier::~CaptureStateNotifier() {
LOG_ALWAYS_FATAL_IF(mListener != nullptr);
@@ -33,11 +33,20 @@
bool CaptureStateNotifier::RegisterListener(const sp<ICaptureStateListener>& listener) {
std::lock_guard<std::mutex> _l(mMutex);
LOG_ALWAYS_FATAL_IF(mListener != nullptr);
+ LOG_ALWAYS_FATAL_IF(listener == nullptr);
ALOGI("Registering a listener");
- mListener = listener;
- sp<IBinder> binder = IInterface::asBinder(mListener);
- binder->linkToDeath(new DeathRecipient(this));
+ sp<IBinder> binder = IInterface::asBinder(listener);
+ if (binder != nullptr) {
+ status_t status = binder->linkToDeath(mDeathRecipient);
+ if (status == NO_ERROR) {
+ mListener = listener;
+ } else {
+ ALOGE("Failed to register death listener: %u", status);
+ }
+ } else {
+ ALOGE("Listener failed to cast to a binder.");
+ }
return mActive;
}
diff --git a/services/audiopolicy/service/CaptureStateNotifier.h b/services/audiopolicy/service/CaptureStateNotifier.h
index 4ca6601..166de2a 100644
--- a/services/audiopolicy/service/CaptureStateNotifier.h
+++ b/services/audiopolicy/service/CaptureStateNotifier.h
@@ -17,6 +17,7 @@
#pragma once
#include <mutex>
+#include <binder/IBinder.h>
#include <utils/StrongPointer.h>
namespace android {
@@ -63,6 +64,7 @@
private:
std::mutex mMutex;
sp<media::ICaptureStateListener> mListener;
+ sp<IBinder::DeathRecipient> mDeathRecipient;
bool mActive;
class DeathRecipient;
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
index 238356e..4c8366f 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
@@ -246,6 +246,8 @@
frameNumber);
return;
}
+ nsecs_t sensorTimestamp = timestamp.data.i64[0];
+
for (auto& physicalMetadata : captureResult.mPhysicalMetadatas) {
camera_metadata_entry timestamp =
physicalMetadata.mPhysicalCameraMetadata.find(ANDROID_SENSOR_TIMESTAMP);
@@ -337,7 +339,7 @@
CameraMetadata(m.mPhysicalCameraMetadata));
}
states.tagMonitor.monitorMetadata(TagMonitor::RESULT,
- frameNumber, timestamp.data.i64[0], captureResult.mMetadata,
+ frameNumber, sensorTimestamp, captureResult.mMetadata,
monitoredPhysicalMetadata);
insertResultLocked(states, &captureResult, frameNumber);
diff --git a/services/mediametrics/AnalyticsState.h b/services/mediametrics/AnalyticsState.h
index 290ed21..e8fedcf 100644
--- a/services/mediametrics/AnalyticsState.h
+++ b/services/mediametrics/AnalyticsState.h
@@ -84,8 +84,11 @@
* delivered.
*
* \param lines the maximum number of lines in the string returned.
+ * \param sinceNs the nanoseconds since Unix epoch to start dump (0 shows all)
+ * \param prefix the desired key prefix to match (nullptr shows all)
*/
- std::pair<std::string, int32_t> dump(int32_t lines = INT32_MAX) const {
+ std::pair<std::string, int32_t> dump(
+ int32_t lines = INT32_MAX, int64_t sinceNs = 0, const char *prefix = nullptr) const {
std::stringstream ss;
int32_t ll = lines;
@@ -94,8 +97,8 @@
--ll;
}
if (ll > 0) {
- auto [s, l] = mTransactionLog.dump(ll);
- ss << s;
+ auto [s, l] = mTransactionLog.dump(ll, sinceNs, prefix);
+ ss << std::move(s);
ll -= l;
}
if (ll > 0) {
@@ -103,8 +106,8 @@
--ll;
}
if (ll > 0) {
- auto [s, l] = mTimeMachine.dump(ll);
- ss << s;
+ auto [s, l] = mTimeMachine.dump(ll, sinceNs, prefix);
+ ss << std::move(s);
ll -= l;
}
return { ss.str(), lines - ll };
diff --git a/services/mediametrics/Android.bp b/services/mediametrics/Android.bp
index ec59ec1..58f3ea8 100644
--- a/services/mediametrics/Android.bp
+++ b/services/mediametrics/Android.bp
@@ -57,6 +57,7 @@
"liblog",
"libmediametrics",
"libmediautils",
+ "libmemunreachable",
"libprotobuf-cpp-lite",
"libstatslog",
"libutils",
diff --git a/services/mediametrics/AudioAnalytics.cpp b/services/mediametrics/AudioAnalytics.cpp
index 126e501..f80516e 100644
--- a/services/mediametrics/AudioAnalytics.cpp
+++ b/services/mediametrics/AudioAnalytics.cpp
@@ -107,14 +107,15 @@
return NO_ERROR;
}
-std::pair<std::string, int32_t> AudioAnalytics::dump(int32_t lines) const
+std::pair<std::string, int32_t> AudioAnalytics::dump(
+ int32_t lines, int64_t sinceNs, const char *prefix) const
{
std::stringstream ss;
int32_t ll = lines;
if (ll > 0) {
- auto [s, l] = mAnalyticsState->dump(ll);
- ss << s;
+ auto [s, l] = mAnalyticsState->dump(ll, sinceNs, prefix);
+ ss << std::move(s);
ll -= l;
}
if (ll > 0) {
@@ -122,8 +123,8 @@
--ll;
}
if (ll > 0) {
- auto [s, l] = mPreviousAnalyticsState->dump(ll);
- ss << s;
+ auto [s, l] = mPreviousAnalyticsState->dump(ll, sinceNs, prefix);
+ ss << std::move(s);
ll -= l;
}
return { ss.str(), lines - ll };
diff --git a/services/mediametrics/AudioAnalytics.h b/services/mediametrics/AudioAnalytics.h
index 4a42e22..ba4c3f2 100644
--- a/services/mediametrics/AudioAnalytics.h
+++ b/services/mediametrics/AudioAnalytics.h
@@ -60,8 +60,17 @@
* delivered.
*
* \param lines the maximum number of lines in the string returned.
+ * \param sinceNs the nanoseconds since Unix epoch to start dump (0 shows all)
+ * \param prefix the desired key prefix to match (nullptr shows all)
*/
- std::pair<std::string, int32_t> dump(int32_t lines = INT32_MAX) const;
+ std::pair<std::string, int32_t> dump(
+ int32_t lines = INT32_MAX, int64_t sinceNs = 0, const char *prefix = nullptr) const;
+
+ void clear() {
+ // underlying state is locked.
+ mPreviousAnalyticsState->clear();
+ mAnalyticsState->clear();
+ }
private:
diff --git a/services/mediametrics/MediaMetricsService.cpp b/services/mediametrics/MediaMetricsService.cpp
index a6fefd2..b9703ba 100644
--- a/services/mediametrics/MediaMetricsService.cpp
+++ b/services/mediametrics/MediaMetricsService.cpp
@@ -26,6 +26,8 @@
#include <audio_utils/clock.h> // clock conversions
#include <binder/IPCThreadState.h> // get calling uid
#include <cutils/properties.h> // for property_get
+#include <mediautils/MemoryLeakTrackUtil.h>
+#include <memunreachable/memunreachable.h>
#include <private/android_filesystem_config.h> // UID
namespace android {
@@ -205,91 +207,112 @@
return NO_ERROR;
}
- // crack any parameters
- const String16 protoOption("--proto");
- const String16 clearOption("--clear");
+ static const String16 allOption("--all");
+ static const String16 clearOption("--clear");
+ static const String16 heapOption("--heap");
+ static const String16 helpOption("--help");
+ static const String16 prefixOption("--prefix");
+ static const String16 sinceOption("--since");
+ static const String16 unreachableOption("--unreachable");
+
+ bool all = false;
bool clear = false;
- const String16 sinceOption("--since");
- nsecs_t ts_since = 0;
- const String16 helpOption("--help");
- const String16 onlyOption("--only");
- std::string only;
- const int n = args.size();
- for (int i = 0; i < n; i++) {
- if (args[i] == clearOption) {
+ bool heap = false;
+ bool unreachable = false;
+ int64_t sinceNs = 0;
+ std::string prefix;
+
+ const size_t n = args.size();
+ for (size_t i = 0; i < n; i++) {
+ if (args[i] == allOption) {
+ all = true;
+ } else if (args[i] == clearOption) {
clear = true;
- } else if (args[i] == protoOption) {
- i++;
- if (i < n) {
- // ignore
- } else {
- result.append("missing value for -proto\n\n");
- }
- } else if (args[i] == sinceOption) {
- i++;
- if (i < n) {
- String8 value(args[i]);
- char *endp;
- const char *p = value.string();
- ts_since = strtoll(p, &endp, 10);
- if (endp == p || *endp != '\0') {
- ts_since = 0;
- }
- } else {
- ts_since = 0;
- }
- // command line is milliseconds; internal units are nano-seconds
- ts_since *= NANOS_PER_MILLISECOND;
- } else if (args[i] == onlyOption) {
- i++;
- if (i < n) {
- String8 value(args[i]);
- only = value.string();
- }
+ } else if (args[i] == heapOption) {
+ heap = true;
} else if (args[i] == helpOption) {
// TODO: consider function area dumping.
// dumpsys media.metrics audiotrack,codec
// or dumpsys media.metrics audiotrack codec
result.append("Recognized parameters:\n");
- result.append("--help this help message\n");
- result.append("--proto # dump using protocol #");
- result.append("--clear clears out saved records\n");
- result.append("--only X process records for component X\n");
- result.append("--since X include records since X\n");
- result.append(" (X is milliseconds since the UNIX epoch)\n");
+ result.append("--all show all records\n");
+ result.append("--clear clear out saved records\n");
+ result.append("--heap show heap usage (top 100)\n");
+ result.append("--help display help\n");
+ result.append("--prefix X process records for component X\n");
+ result.append("--since X X < 0: records from -X seconds in the past\n");
+ result.append(" X = 0: ignore\n");
+ result.append(" X > 0: records from X seconds since Unix epoch\n");
+ result.append("--unreachable show unreachable memory (leaks)\n");
write(fd, result.string(), result.size());
return NO_ERROR;
+ } else if (args[i] == prefixOption) {
+ ++i;
+ if (i < n) {
+ prefix = String8(args[i]).string();
+ }
+ } else if (args[i] == sinceOption) {
+ ++i;
+ if (i < n) {
+ String8 value(args[i]);
+ char *endp;
+ const char *p = value.string();
+ long long sec = strtoll(p, &endp, 10);
+ if (endp == p || *endp != '\0' || sec == 0) {
+ sinceNs = 0;
+ } else if (sec < 0) {
+ sinceNs = systemTime(SYSTEM_TIME_REALTIME) + sec * NANOS_PER_SECOND;
+ } else {
+ sinceNs = sec * NANOS_PER_SECOND;
+ }
+ }
+ } else if (args[i] == unreachableOption) {
+ unreachable = true;
}
}
{
std::lock_guard _l(mLock);
- result.appendFormat("Dump of the %s process:\n", kServiceName);
- dumpHeaders_l(result, ts_since);
- dumpRecent_l(result, ts_since, only.c_str());
-
if (clear) {
mItemsDiscarded += mItems.size();
mItems.clear();
- // shall we clear the summary data too?
- }
- // TODO: maybe consider a better way of dumping audio analytics info.
- constexpr int32_t linesToDump = 1000;
- auto [ dumpString, lines ] = mAudioAnalytics.dump(linesToDump);
- result.append(dumpString.c_str());
- if (lines == linesToDump) {
- result.append("-- some lines may be truncated --\n");
+ mAudioAnalytics.clear();
+ } else {
+ result.appendFormat("Dump of the %s process:\n", kServiceName);
+ const char *prefixptr = prefix.size() > 0 ? prefix.c_str() : nullptr;
+ dumpHeaders_l(result, sinceNs, prefixptr);
+ dumpQueue_l(result, sinceNs, prefixptr);
+
+ // TODO: maybe consider a better way of dumping audio analytics info.
+ const int32_t linesToDump = all ? INT32_MAX : 1000;
+ auto [ dumpString, lines ] = mAudioAnalytics.dump(linesToDump, sinceNs, prefixptr);
+ result.append(dumpString.c_str());
+ if (lines == linesToDump) {
+ result.append("-- some lines may be truncated --\n");
+ }
}
}
-
write(fd, result.string(), result.size());
+
+ // Check heap and unreachable memory outside of lock.
+ if (heap) {
+ dprintf(fd, "\nDumping heap:\n");
+ std::string s = dumpMemoryAddresses(100 /* limit */);
+ write(fd, s.c_str(), s.size());
+ }
+ if (unreachable) {
+ dprintf(fd, "\nDumping unreachable memory:\n");
+ // TODO - should limit be an argument parameter?
+ std::string s = GetUnreachableMemoryString(true /* contents */, 100 /* limit */);
+ write(fd, s.c_str(), s.size());
+ }
return NO_ERROR;
}
// dump headers
-void MediaMetricsService::dumpHeaders_l(String8 &result, nsecs_t ts_since)
+void MediaMetricsService::dumpHeaders_l(String8 &result, int64_t sinceNs, const char* prefix)
{
if (mediametrics::Item::isEnabled()) {
result.append("Metrics gathering: enabled\n");
@@ -303,54 +326,36 @@
"Records Discarded: %lld (by Count: %lld by Expiration: %lld)\n",
(long long)mItemsDiscarded, (long long)mItemsDiscardedCount,
(long long)mItemsDiscardedExpire);
- if (ts_since != 0) {
+ if (prefix != nullptr) {
+ result.appendFormat("Restricting to prefix %s", prefix);
+ }
+ if (sinceNs != 0) {
result.appendFormat(
"Emitting Queue entries more recent than: %lld\n",
- (long long)ts_since);
+ (long long)sinceNs);
}
}
-void MediaMetricsService::dumpRecent_l(
- String8 &result, nsecs_t ts_since, const char * only)
+// TODO: should prefix be a set<string>?
+void MediaMetricsService::dumpQueue_l(String8 &result, int64_t sinceNs, const char* prefix)
{
- if (only != nullptr && *only == '\0') {
- only = nullptr;
- }
- result.append("\nFinalized Metrics (oldest first):\n");
- dumpQueue_l(result, ts_since, only);
-
- // show who is connected and injecting records?
- // talk about # records fed to the 'readers'
- // talk about # records we discarded, perhaps "discarded w/o reading" too
-}
-
-void MediaMetricsService::dumpQueue_l(String8 &result) {
- dumpQueue_l(result, (nsecs_t) 0, nullptr /* only */);
-}
-
-void MediaMetricsService::dumpQueue_l(
- String8 &result, nsecs_t ts_since, const char * only) {
- int slot = 0;
-
if (mItems.empty()) {
result.append("empty\n");
- } else {
- for (const auto &item : mItems) {
- nsecs_t when = item->getTimestamp();
- if (when < ts_since) {
- continue;
- }
- // TODO: Only should be a set<string>
- if (only != nullptr &&
- item->getKey() /* std::string */ != only) {
- ALOGV("%s: omit '%s', it's not '%s'",
- __func__, item->getKey().c_str(), only);
- continue;
- }
- result.appendFormat("%5d: %s\n",
- slot, item->toString().c_str());
- slot++;
+ return;
+ }
+
+ int slot = 0;
+ for (const auto &item : mItems) { // TODO: consider std::lower_bound() on mItems
+ if (item->getTimestamp() < sinceNs) { // sinceNs == 0 means all items shown
+ continue;
}
+ if (prefix != nullptr && !startsWith(item->getKey(), prefix)) {
+ ALOGV("%s: omit '%s', it's not '%s'",
+ __func__, item->getKey().c_str(), prefix);
+ continue;
+ }
+ result.appendFormat("%5d: %s\n", slot, item->toString().c_str());
+ slot++;
}
}
diff --git a/services/mediametrics/MediaMetricsService.h b/services/mediametrics/MediaMetricsService.h
index 935bee2..a93f7fb 100644
--- a/services/mediametrics/MediaMetricsService.h
+++ b/services/mediametrics/MediaMetricsService.h
@@ -85,11 +85,8 @@
bool expirations_l(const std::shared_ptr<const mediametrics::Item>& item);
// support for generating output
- void dumpQueue_l(String8 &result);
- void dumpQueue_l(String8 &result, nsecs_t, const char *only);
- void dumpHeaders_l(String8 &result, nsecs_t ts_since);
- void dumpSummaries_l(String8 &result, nsecs_t ts_since, const char * only);
- void dumpRecent_l(String8 &result, nsecs_t ts_since, const char * only);
+ void dumpQueue_l(String8 &result, int64_t sinceNs, const char* prefix);
+ void dumpHeaders_l(String8 &result, int64_t sinceNs, const char* prefix);
// The following variables accessed without mLock
diff --git a/services/mediametrics/TimeMachine.h b/services/mediametrics/TimeMachine.h
index a4c3693..75819ba 100644
--- a/services/mediametrics/TimeMachine.h
+++ b/services/mediametrics/TimeMachine.h
@@ -149,8 +149,11 @@
int32_t ll = lines;
for (auto& tsPair : mPropertyMap) {
if (ll <= 0) break;
- ss << dump(mKey, tsPair, time);
- --ll;
+ std::string s = dump(mKey, tsPair, time);
+ if (s.size() > 0) {
+ --ll;
+ ss << std::move(s);
+ }
}
return { ss.str(), lines - ll };
}
@@ -165,7 +168,7 @@
const auto timeSequence = tsPair.second;
auto eptr = timeSequence.lower_bound(time);
if (eptr == timeSequence.end()) {
- return tsPair.first + "={};\n";
+ return {}; // don't dump anything. tsPair.first + "={};\n";
}
std::stringstream ss;
ss << key << "." << tsPair.first << "={";
@@ -407,25 +410,23 @@
*
* \param lines the maximum number of lines in the string returned.
* \param key selects only that key.
- * \param time to start the dump from.
+ * \param sinceNs the nanoseconds since Unix epoch to start dump (0 shows all)
+ * \param prefix the desired key prefix to match (nullptr shows all)
*/
std::pair<std::string, int32_t> dump(
- int32_t lines = INT32_MAX, const std::string &key = {}, int64_t time = 0) const {
+ int32_t lines = INT32_MAX, int64_t sinceNs = 0, const char *prefix = nullptr) const {
std::lock_guard lock(mLock);
- if (!key.empty()) { // use std::regex
- const auto it = mHistory.find(key);
- if (it == mHistory.end()) return {};
- std::lock_guard lock(getLockForKey(it->first));
- return it->second->dump(lines, time);
- }
-
std::stringstream ss;
int32_t ll = lines;
- for (const auto &[lkey, lhist] : mHistory) {
- std::lock_guard lock(getLockForKey(lkey));
- if (lines <= 0) break;
- auto [s, l] = lhist->dump(ll, time);
- ss << s;
+
+ for (auto it = prefix != nullptr ? mHistory.lower_bound(prefix) : mHistory.begin();
+ it != mHistory.end();
+ ++it) {
+ if (ll <= 0) break;
+ if (prefix != nullptr && !startsWith(it->first, prefix)) break;
+ std::lock_guard lock(getLockForKey(it->first));
+ auto [s, l] = it->second->dump(ll, sinceNs);
+ ss << std::move(s);
ll -= l;
}
return { ss.str(), lines - ll };
diff --git a/services/mediametrics/TransactionLog.h b/services/mediametrics/TransactionLog.h
index 190a99e..2359eec 100644
--- a/services/mediametrics/TransactionLog.h
+++ b/services/mediametrics/TransactionLog.h
@@ -127,8 +127,11 @@
* for subsequent line limiting.
*
* \param lines the maximum number of lines in the string returned.
+ * \param sinceNs the nanoseconds since Unix epoch to start dump (0 shows all)
+ * \param prefix the desired key prefix to match (nullptr shows all)
*/
- std::pair<std::string, int32_t> dump(int32_t lines) const {
+ std::pair<std::string, int32_t> dump(
+ int32_t lines, int64_t sinceNs, const char *prefix = nullptr) const {
std::stringstream ss;
int32_t ll = lines;
std::lock_guard lock(mLock);
@@ -138,26 +141,25 @@
ss << "Consolidated:\n";
--ll;
}
- for (const auto &log : mLog) {
- if (ll <= 0) break;
- ss << " " << log.second->toString() << "\n";
- --ll;
- }
+ auto [s, l] = dumpMapTimeItem(mLog, ll, sinceNs, prefix);
+ ss << std::move(s);
+ ll -= l;
// Grouped by item key (category)
if (ll > 0) {
ss << "Categorized:\n";
--ll;
}
- for (const auto &itemMap : mItemMap) {
+
+ for (auto it = prefix != nullptr ? mItemMap.lower_bound(prefix) : mItemMap.begin();
+ it != mItemMap.end();
+ ++it) {
if (ll <= 0) break;
- ss << " " << itemMap.first << "\n";
- --ll;
- for (const auto &item : itemMap.second) {
- if (ll <= 0) break;
- ss << " " << item.second->toString() << "\n";
- --ll;
- }
+ if (prefix != nullptr && !startsWith(it->first, prefix)) break;
+ auto [s, l] = dumpMapTimeItem(it->second, ll - 1, sinceNs, prefix);
+ if (l == 0) continue; // don't show empty groups (due to sinceNs).
+ ss << " " << it->first << "\n" << std::move(s);
+ ll -= l + 1;
}
return { ss.str(), lines - ll };
}
@@ -184,6 +186,24 @@
using MapTimeItem =
std::multimap<int64_t /* time */, std::shared_ptr<const mediametrics::Item>>;
+ static std::pair<std::string, int32_t> dumpMapTimeItem(
+ const MapTimeItem& mapTimeItem,
+ int32_t lines, int64_t sinceNs = 0, const char *prefix = nullptr) {
+ std::stringstream ss;
+ int32_t ll = lines;
+ // Note: for our data, mapTimeItem.lower_bound(0) == mapTimeItem.begin().
+ for (auto it = mapTimeItem.lower_bound(sinceNs);
+ it != mapTimeItem.end(); ++it) {
+ if (ll <= 0) break;
+ if (prefix != nullptr && !startsWith(it->second->getKey(), prefix)) {
+ continue;
+ }
+ ss << " " << it->second->toString() << "\n";
+ --ll;
+ }
+ return { ss.str(), lines - ll };
+ }
+
// GUARDED_BY mLock
/**
* Garbage collects if the TimeMachine size exceeds the high water mark.