Expand mediaextractor dumpsys

Bug: 22775369
Change-Id: I3366a52ba7a00d1685a2211465f2f18f143d0efc
diff --git a/include/media/IDataSource.h b/include/media/IDataSource.h
index 09009f0..838e29f 100644
--- a/include/media/IDataSource.h
+++ b/include/media/IDataSource.h
@@ -20,6 +20,7 @@
 #include <binder/IInterface.h>
 #include <media/stagefright/foundation/ABase.h>
 #include <utils/Errors.h>
+#include <utils/String8.h>
 
 namespace android {
 
@@ -44,6 +45,8 @@
     // Get the flags of the source.
     // Refer to DataSource:Flags for the definition of the flags.
     virtual uint32_t getFlags() = 0;
+    // get a description of the source, e.g. the url or filename it is based on
+    virtual String8 toString() = 0;
 
 private:
     DISALLOW_EVIL_CONSTRUCTORS(IDataSource);
diff --git a/include/media/IMediaExtractor.h b/include/media/IMediaExtractor.h
index 9f7a719..d9fcd89 100644
--- a/include/media/IMediaExtractor.h
+++ b/include/media/IMediaExtractor.h
@@ -19,6 +19,7 @@
 #define IMEDIA_EXTRACTOR_BASE_H_
 
 #include <media/IMediaSource.h>
+#include <media/IDataSource.h>
 
 namespace android {
 
@@ -69,6 +70,17 @@
                                 uint32_t flags = 0);
 };
 
+void registerMediaExtractor(
+        const sp<IMediaExtractor> &extractor,
+        const sp<IDataSource> &source,
+        const char *mime);
+
+void registerMediaSource(
+        const sp<IMediaExtractor> &extractor,
+        const sp<IMediaSource> &source);
+
+status_t dumpExtractors(int fd, const Vector<String16>& args);
+
 
 }  // namespace android
 
diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h
index c5e09c0..c5df1f6 100644
--- a/include/media/stagefright/DataSource.h
+++ b/include/media/stagefright/DataSource.h
@@ -78,6 +78,10 @@
         return 0;
     }
 
+    virtual String8 toString() {
+        return String8("<unspecified>");
+    }
+
     virtual status_t reconnectAtOffset(off64_t offset) {
         return ERROR_UNSUPPORTED;
     }
diff --git a/include/media/stagefright/FileSource.h b/include/media/stagefright/FileSource.h
index 266168b..b6349e0 100644
--- a/include/media/stagefright/FileSource.h
+++ b/include/media/stagefright/FileSource.h
@@ -43,6 +43,10 @@
 
     virtual void getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client);
 
+    virtual String8 toString() {
+        return mName;
+    }
+
 protected:
     virtual ~FileSource();
 
@@ -51,6 +55,7 @@
     int64_t mOffset;
     int64_t mLength;
     Mutex mLock;
+    String8 mName;
 
     /*for DRM*/
     sp<DecryptHandle> mDecryptHandle;
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index a9ae49b..4f7426d 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -258,6 +258,7 @@
 
     bool hasData(uint32_t key) const;
 
+    String8 toString() const;
     void dumpToLog() const;
 
     status_t writeToParcel(Parcel &parcel);
@@ -278,7 +279,8 @@
         void clear();
         void setData(uint32_t type, const void *data, size_t size);
         void getData(uint32_t *type, const void **data, size_t *size) const;
-        String8 asString() const;
+        // may include hexdump of binary data if verbose=true
+        String8 asString(bool verbose) const;
 
     private:
         uint32_t mType;
diff --git a/media/libmedia/IDataSource.cpp b/media/libmedia/IDataSource.cpp
index ac864a4..7aeba5a 100644
--- a/media/libmedia/IDataSource.cpp
+++ b/media/libmedia/IDataSource.cpp
@@ -33,6 +33,7 @@
     GET_SIZE,
     CLOSE,
     GET_FLAGS,
+    TO_STRING,
 };
 
 struct BpDataSource : public BpInterface<IDataSource> {
@@ -76,6 +77,13 @@
         remote()->transact(GET_FLAGS, data, &reply);
         return reply.readUint32();
     }
+
+    virtual String8 toString() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IDataSource::getInterfaceDescriptor());
+        remote()->transact(TO_STRING, data, &reply);
+        return reply.readString8();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(DataSource, "android.media.IDataSource");
@@ -113,6 +121,12 @@
             reply->writeUint32(getFlags());
             return NO_ERROR;
         } break;
+        case TO_STRING: {
+            CHECK_INTERFACE(IDataSource, data, reply);
+            reply->writeString8(toString());
+            return NO_ERROR;
+        } break;
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
index 76d5648..b13b69f 100644
--- a/media/libmedia/IMediaExtractor.cpp
+++ b/media/libmedia/IMediaExtractor.cpp
@@ -21,6 +21,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <binder/IPCThreadState.h>
 #include <binder/Parcel.h>
 #include <media/IMediaExtractor.h>
 #include <media/stagefright/MetaData.h>
@@ -145,7 +146,9 @@
             CHECK_INTERFACE(IMediaExtractor, data, reply);
             uint32_t idx;
             if (data.readUint32(&idx) == NO_ERROR) {
-                return reply->writeStrongBinder(IInterface::asBinder(getTrack((size_t(idx)))));
+                const sp<IMediaSource> track = getTrack(size_t(idx));
+                registerMediaSource(this, track);
+                return reply->writeStrongBinder(IInterface::asBinder(track));
             }
             return UNKNOWN_ERROR;
         }
@@ -177,6 +180,90 @@
     }
 }
 
+typedef struct {
+    String8 mime;
+    String8 name;
+    String8 sourceDescription;
+    pid_t owner;
+    wp<IMediaExtractor> extractor;
+    Vector<wp<IMediaSource>> tracks;
+    Vector<String8> trackDescriptions;
+    String8 toString() const;
+} ExtractorInstance;
+
+String8 ExtractorInstance::toString() const {
+    String8 str = name;
+    str.append(" for mime ");
+    str.append(mime);
+    str.append(", source ");
+    str.append(sourceDescription);
+    str.append(String8::format(", pid %d: ", owner));
+    if (extractor.promote() == NULL) {
+        str.append("deleted\n");
+    } else {
+        str.append("active\n");
+    }
+    for (size_t i = 0; i < tracks.size(); i++) {
+        const String8 desc = trackDescriptions.itemAt(i);
+        str.appendFormat("    track {%s} ", desc.string());
+        const sp<IMediaSource> source = tracks.itemAt(i).promote();
+        if (source == NULL) {
+            str.append(": deleted\n");
+        } else {
+            str.appendFormat(": active\n");
+        }
+    }
+    return str;
+}
+
+static Vector<ExtractorInstance> extractors;
+
+void registerMediaSource(
+        const sp<IMediaExtractor> &ex,
+        const sp<IMediaSource> &source) {
+    for (size_t i = 0; i < extractors.size(); i++) {
+        ExtractorInstance &instance = extractors.editItemAt(i);
+        sp<IMediaExtractor> extractor = instance.extractor.promote();
+        if (extractor != NULL && extractor == ex) {
+            if (instance.tracks.size() > 5) {
+                instance.tracks.resize(5);
+            }
+            instance.tracks.push_front(source);
+            instance.trackDescriptions.add(source->getFormat()->toString());
+            break;
+        }
+    }
+}
+
+void registerMediaExtractor(
+        const sp<IMediaExtractor> &extractor,
+        const sp<IDataSource> &source,
+        const char *mime) {
+    ExtractorInstance ex;
+    ex.mime = mime == NULL ? "NULL" : mime;
+    ex.name = extractor->name();
+    ex.sourceDescription = source->toString();
+    ex.owner = IPCThreadState::self()->getCallingPid();
+    ex.extractor = extractor;
+
+    if (extractors.size() > 10) {
+        extractors.resize(10);
+    }
+    extractors.push_front(ex);
+}
+
+status_t dumpExtractors(int fd, const Vector<String16>&) {
+    String8 out;
+    out.append("Recent extractors, most recent first:\n");
+    for (size_t i = 0; i < extractors.size(); i++) {
+        const ExtractorInstance &instance = extractors.itemAt(i);
+        out.append("  ");
+        out.append(instance.toString());
+    }
+    write(fd, out.string(), out.size());
+    return OK;
+}
+
 
 }  // namespace android
 
diff --git a/media/libstagefright/CallbackDataSource.cpp b/media/libstagefright/CallbackDataSource.cpp
index bcbd78d..f14d34d 100644
--- a/media/libstagefright/CallbackDataSource.cpp
+++ b/media/libstagefright/CallbackDataSource.cpp
@@ -34,6 +34,8 @@
       mIsClosed(false) {
     // Set up the buffer to read into.
     mMemory = mIDataSource->getIMemory();
+    mName = String8::format("CallbackDataSource(%s)", mIDataSource->toString().string());
+
 }
 
 CallbackDataSource::~CallbackDataSource() {
@@ -109,6 +111,7 @@
 
 TinyCacheSource::TinyCacheSource(const sp<DataSource>& source)
     : mSource(source), mCachedOffset(0), mCachedSize(0) {
+    mName = String8::format("TinyCacheSource(%s)", mSource->toString().string());
 }
 
 status_t TinyCacheSource::initCheck() const {
diff --git a/media/libstagefright/FileSource.cpp b/media/libstagefright/FileSource.cpp
index 52688b1..5b92f91 100644
--- a/media/libstagefright/FileSource.cpp
+++ b/media/libstagefright/FileSource.cpp
@@ -33,12 +33,16 @@
     : mFd(-1),
       mOffset(0),
       mLength(-1),
+      mName("<null>"),
       mDecryptHandle(NULL),
       mDrmManagerClient(NULL),
       mDrmBufOffset(0),
       mDrmBufSize(0),
       mDrmBuf(NULL){
 
+    if (filename) {
+        mName = String8::format("FileSource(%s)", filename);
+    }
     ALOGV("%s", filename);
     mFd = open(filename, O_LARGEFILE | O_RDONLY);
 
@@ -53,6 +57,7 @@
     : mFd(fd),
       mOffset(offset),
       mLength(length),
+      mName("<null>"),
       mDecryptHandle(NULL),
       mDrmManagerClient(NULL),
       mDrmBufOffset(0),
@@ -85,6 +90,13 @@
                 (long long) offset, (long long) length,
                 (long long) mOffset, (long long) mLength);
     }
+
+    mName = String8::format(
+            "FileSource(fd(%s), %lld, %lld)",
+            nameForFd(fd).c_str(),
+            (long long) mOffset,
+            (long long) mLength);
+
 }
 
 FileSource::~FileSource() {
diff --git a/media/libstagefright/HTTPBase.cpp b/media/libstagefright/HTTPBase.cpp
index 068a77f..0f24329 100644
--- a/media/libstagefright/HTTPBase.cpp
+++ b/media/libstagefright/HTTPBase.cpp
@@ -38,6 +38,7 @@
       mPrevBandwidthMeasureTimeUs(0),
       mPrevEstimatedBandWidthKbps(0),
       mBandWidthCollectFreqMs(5000) {
+    mName = String8("HTTPBase(<disconnected>)");
 }
 
 void HTTPBase::addBandwidthMeasurement(
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index fe66a58..1c6c882 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -87,10 +87,12 @@
     virtual status_t getSize(off64_t* size);
     virtual void close();
     virtual uint32_t getFlags();
+    virtual String8 toString();
 
 private:
     sp<IMemory> mMemory;
     sp<DataSource> mSource;
+    String8 mName;
     RemoteDataSource(const sp<DataSource> &source);
     DISALLOW_EVIL_CONSTRUCTORS(RemoteDataSource);
 };
@@ -106,6 +108,7 @@
     if (mMemory == NULL) {
         ALOGE("Failed to allocate memory!");
     }
+    mName = String8::format("RemoteDataSource(%s)", mSource->toString().string());
 }
 RemoteDataSource::~RemoteDataSource() {
     close();
@@ -127,6 +130,10 @@
     return mSource->flags();
 }
 
+String8 RemoteDataSource::toString() {
+    return mName;
+}
+
 // static
 sp<IMediaExtractor> MediaExtractor::Create(
         const sp<DataSource> &source, const char *mime) {
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp
index d6255d6..453db03 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libstagefright/NuCachedSource2.cpp
@@ -224,6 +224,8 @@
     // So whenever we call DataSource::readAt it may end up in a call to
     // IMediaHTTPConnection::readAt and therefore call back into JAVA.
     mLooper->start(false /* runOnCallingThread */, true /* canCallJava */);
+
+    mName = String8::format("NuCachedSource2(%s)", mSource->toString().string());
 }
 
 NuCachedSource2::~NuCachedSource2() {
diff --git a/media/libstagefright/foundation/MetaData.cpp b/media/libstagefright/foundation/MetaData.cpp
index b847eed..b4abc60 100644
--- a/media/libstagefright/foundation/MetaData.cpp
+++ b/media/libstagefright/foundation/MetaData.cpp
@@ -316,7 +316,7 @@
     mSize = 0;
 }
 
-String8 MetaData::typed_data::asString() const {
+String8 MetaData::typed_data::asString(bool verbose) const {
     String8 out;
     const void *data = storage();
     switch(mType) {
@@ -348,7 +348,7 @@
 
         default:
             out = String8::format("(unknown type %d, size %zu)", mType, mSize);
-            if (mSize <= 48) { // if it's less than three lines of hex data, dump it
+            if (verbose && mSize <= 48) { // if it's less than three lines of hex data, dump it
                 AString foo;
                 hexdump(data, mSize, 0, &foo);
                 out.append("\n");
@@ -367,13 +367,27 @@
     s[4] = '\0';
 }
 
+String8 MetaData::toString() const {
+    String8 s;
+    for (int i = mItems.size(); --i >= 0;) {
+        int32_t key = mItems.keyAt(i);
+        char cc[5];
+        MakeFourCCString(key, cc);
+        const typed_data &item = mItems.valueAt(i);
+        s.appendFormat("%s: %s", cc, item.asString(false).string());
+        if (i != 0) {
+            s.append(", ");
+        }
+    }
+    return s;
+}
 void MetaData::dumpToLog() const {
     for (int i = mItems.size(); --i >= 0;) {
         int32_t key = mItems.keyAt(i);
         char cc[5];
         MakeFourCCString(key, cc);
         const typed_data &item = mItems.valueAt(i);
-        ALOGI("%s: %s", cc, item.asString().string());
+        ALOGI("%s: %s", cc, item.asString(true /* verbose */).string());
     }
 }
 
diff --git a/media/libstagefright/http/MediaHTTP.cpp b/media/libstagefright/http/MediaHTTP.cpp
index 801ff26..76ec625 100644
--- a/media/libstagefright/http/MediaHTTP.cpp
+++ b/media/libstagefright/http/MediaHTTP.cpp
@@ -65,10 +65,16 @@
 
     mCachedSizeValid = false;
 
+    if (success) {
+        AString sanitized = uriDebugString(uri);
+        mName = String8::format("MediaHTTP(%s)", sanitized.c_str());
+    }
+
     return success ? OK : UNKNOWN_ERROR;
 }
 
 void MediaHTTP::disconnect() {
+    mName = String8("MediaHTTP(<disconnected>)");
     if (mInitCheck != OK) {
         return;
     }
diff --git a/media/libstagefright/include/CallbackDataSource.h b/media/libstagefright/include/CallbackDataSource.h
index 9b33810..43e9b8d 100644
--- a/media/libstagefright/include/CallbackDataSource.h
+++ b/media/libstagefright/include/CallbackDataSource.h
@@ -38,11 +38,15 @@
     virtual status_t getSize(off64_t *size);
     virtual uint32_t flags();
     virtual void close();
+    virtual String8 toString() {
+        return mName;
+    }
 
 private:
     sp<IDataSource> mIDataSource;
     sp<IMemory> mMemory;
     bool mIsClosed;
+    String8 mName;
 
     DISALLOW_EVIL_CONSTRUCTORS(CallbackDataSource);
 };
@@ -61,6 +65,9 @@
     virtual status_t getSize(off64_t* size);
     virtual uint32_t flags();
     virtual void close() { mSource->close(); }
+    virtual String8 toString() {
+        return mName;
+    }
 
 private:
     // 2kb comes from experimenting with the time-to-first-frame from a MediaPlayer
@@ -74,6 +81,7 @@
     uint8_t mCache[kCacheSize];
     off64_t mCachedOffset;
     size_t mCachedSize;
+    String8 mName;
 
     DISALLOW_EVIL_CONSTRUCTORS(TinyCacheSource);
 };
diff --git a/media/libstagefright/include/HTTPBase.h b/media/libstagefright/include/HTTPBase.h
index 0c66e27..d325e30 100644
--- a/media/libstagefright/include/HTTPBase.h
+++ b/media/libstagefright/include/HTTPBase.h
@@ -56,8 +56,13 @@
     static void RegisterSocketUserMark(int sockfd, uid_t uid);
     static void UnRegisterSocketUserMark(int sockfd);
 
+    virtual String8 toString() {
+        return mName;
+    }
+
 protected:
     virtual void addBandwidthMeasurement(size_t numBytes, int64_t delayUs);
+    String8 mName;
 
 private:
     struct BandwidthEntry {
diff --git a/media/libstagefright/include/NuCachedSource2.h b/media/libstagefright/include/NuCachedSource2.h
index a29bdf9..2639280 100644
--- a/media/libstagefright/include/NuCachedSource2.h
+++ b/media/libstagefright/include/NuCachedSource2.h
@@ -48,6 +48,10 @@
 
     virtual String8 getMIMEType() const;
 
+    virtual String8 toString() {
+        return mName;
+    }
+
     ////////////////////////////////////////////////////////////////////////////
 
     size_t cachedSize();
@@ -99,6 +103,7 @@
     sp<DataSource> mSource;
     sp<AHandlerReflector<NuCachedSource2> > mReflector;
     sp<ALooper> mLooper;
+    String8 mName;
 
     Mutex mSerializer;
     mutable Mutex mLock;
diff --git a/services/mediaextractor/MediaExtractorService.cpp b/services/mediaextractor/MediaExtractorService.cpp
index a2b35f6..0c93af1 100644
--- a/services/mediaextractor/MediaExtractorService.cpp
+++ b/services/mediaextractor/MediaExtractorService.cpp
@@ -26,69 +26,29 @@
 
 namespace android {
 
-typedef struct {
-    String8 mime;
-    String8 name;
-    pid_t owner;
-    wp<MediaExtractor> extractor;
-    String8 toString() {
-        String8 str = name;
-        str.append(" for mime ");
-        str.append(mime);
-        str.append(String8::format(", pid %d: ", owner));
-        if (extractor.promote() == NULL) {
-            str.append("deleted");
-        } else {
-            str.append("active");
-        }
-        return str;
-    }
-} ExtractorInstance;
-
-static Vector<ExtractorInstance> extractors;
-
 sp<IMediaExtractor> MediaExtractorService::makeExtractor(
         const sp<IDataSource> &remoteSource, const char *mime) {
     ALOGV("@@@ MediaExtractorService::makeExtractor for %s", mime);
 
     sp<DataSource> localSource = DataSource::CreateFromIDataSource(remoteSource);
 
-    sp<MediaExtractor> ret = MediaExtractor::CreateFromService(localSource, mime);
+    sp<IMediaExtractor> ret = MediaExtractor::CreateFromService(localSource, mime);
 
     ALOGV("extractor service created %p (%s)",
             ret.get(),
             ret == NULL ? "" : ret->name());
 
     if (ret != NULL) {
-        ExtractorInstance ex;
-        ex.mime = mime == NULL ? "NULL" : mime;
-        ex.name = ret->name();
-        ex.owner = IPCThreadState::self()->getCallingPid();
-        ex.extractor = ret;
-
-        if (extractors.size() > 10) {
-            extractors.resize(10);
-        }
-        extractors.push_front(ex);
+        registerMediaExtractor(ret, remoteSource, mime);
     }
 
     return ret;
 }
 
 status_t MediaExtractorService::dump(int fd, const Vector<String16>& args) {
-    String8 out;
-    out.append("Recent extractors, most recent first:\n");
-    for (size_t i = 0; i < extractors.size(); i++) {
-        ExtractorInstance ex = extractors.itemAt(i);
-        out.append("  ");
-        out.append(ex.toString());
-        out.append("\n");
-    }
-    write(fd, out.string(), out.size());
-    return OK;
+    return dumpExtractors(fd, args);
 }
 
-
 status_t MediaExtractorService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
         uint32_t flags)
 {