Merge "Introduce AMediaDataSource_newUri API"
diff --git a/media/audioserver/Android.mk b/media/audioserver/Android.mk
index a53a629..1ca0fdc 100644
--- a/media/audioserver/Android.mk
+++ b/media/audioserver/Android.mk
@@ -55,13 +55,9 @@
 #   both    to build both 32 bit and 64 bit libraries,
 #           and use primary target architecture (32 or 64) for audioserver.
 #   first   to build libraries and audioserver for the primary target architecture only.
-#   <empty> to build both 32 and 64 bit libraries and 32 bit audioserver.
+#   <empty> to build both 32 and 64 bit libraries and primary target audioserver.
 
-ifeq ($(strip $(AUDIOSERVER_MULTILIB)),)
-LOCAL_MULTILIB := 32
-else
 LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-endif
 
 LOCAL_MODULE := audioserver
 
diff --git a/media/extractors/mpeg2/Android.bp b/media/extractors/mpeg2/Android.bp
index 5e4a592..40314dc 100644
--- a/media/extractors/mpeg2/Android.bp
+++ b/media/extractors/mpeg2/Android.bp
@@ -25,6 +25,10 @@
         "libstagefright_foundation",
     ],
 
+    header_libs: [
+        "libbase_headers",
+    ],
+
     static_libs: [
         "libstagefright_mpeg2support",
         "libutils",
diff --git a/media/extractors/mpeg2/MPEG2TSExtractor.cpp b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
index cbe8556..0d7c831 100644
--- a/media/extractors/mpeg2/MPEG2TSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
@@ -20,6 +20,8 @@
 #include <inttypes.h>
 #include <utils/Log.h>
 
+#include <android-base/macros.h>
+
 #include "MPEG2TSExtractor.h"
 
 #include <media/DataSourceBase.h>
@@ -512,7 +514,7 @@
         case MediaTrack::ReadOptions::SEEK_CLOSEST:
             ALOGW("seekMode not supported: %d; falling back to PREVIOUS_SYNC",
                     seekMode);
-            // fall-through
+            FALLTHROUGH_INTENDED;
         case MediaTrack::ReadOptions::SEEK_PREVIOUS_SYNC:
             if (index == 0) {
                 ALOGW("Previous sync not found; starting from the earliest "
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 9fe9ee5..e150f2b 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -3,6 +3,7 @@
     vendor_available: true,
     export_include_dirs: ["include"],
     header_libs:[
+        "libbase_headers",
         "libgui_headers",
         "libstagefright_headers",
         "media_plugin_headers",
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index 721a043..92cfb1c 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -20,6 +20,7 @@
 
 #include <inttypes.h>
 
+#include <android-base/macros.h>
 #include <utils/Log.h>
 #include <media/mediarecorder.h>
 #include <binder/IServiceManager.h>
@@ -597,7 +598,8 @@
             if (OK != ret) {
                 return ret;  // No need to continue
             }
-        }  // Intentional fall through
+            FALLTHROUGH_INTENDED;
+        }
         case MEDIA_RECORDER_INITIALIZED:
             ret = close();
             break;
diff --git a/media/libmediaextractor/include/media/DataSourceBase.h b/media/libmediaextractor/include/media/DataSourceBase.h
index 51993da..fc620fd 100644
--- a/media/libmediaextractor/include/media/DataSourceBase.h
+++ b/media/libmediaextractor/include/media/DataSourceBase.h
@@ -66,6 +66,12 @@
 
     virtual void close() {};
 
+    virtual void disconnect() {}
+
+    virtual ssize_t getAvailableSize(status_t * /*err*/) {
+        return -1;
+    }
+
 protected:
     virtual ~DataSourceBase() {}
 
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
index 4b0a960..1fe2efa 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
@@ -34,8 +34,7 @@
     MEDIA2_SET_VIDEO_SIZE    = 5,
     MEDIA2_STARTED           = 6,
     MEDIA2_PAUSED            = 7,
-    MEDIA2_STOPPED           = 8,
-    MEDIA2_SKIPPED           = 9,
+    MEDIA2_SKIPPED           = 8,
     MEDIA2_NOTIFY_TIME       = 98,
     MEDIA2_TIMED_TEXT        = 99,
     MEDIA2_ERROR             = 100,
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
index 2f90825..e51727b 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
@@ -487,7 +487,7 @@
 status_t NuPlayer2::setPlaybackSettings(const AudioPlaybackRate &rate) {
     // do some cursory validation of the settings here. audio modes are
     // only validated when set on the audiosink.
-     if ((rate.mSpeed != 0.f && rate.mSpeed < AUDIO_TIMESTRETCH_SPEED_MIN)
+     if (rate.mSpeed < AUDIO_TIMESTRETCH_SPEED_MIN
             || rate.mSpeed > AUDIO_TIMESTRETCH_SPEED_MAX
             || rate.mPitch < AUDIO_TIMESTRETCH_SPEED_MIN
             || rate.mPitch > AUDIO_TIMESTRETCH_SPEED_MAX) {
@@ -986,8 +986,7 @@
             if (mRenderer != NULL) {
                 // AudioSink allows only 1.f and 0.f for offload mode.
                 // For other speed, switch to non-offload mode.
-                if (mOffloadAudio && ((rate.mSpeed != 0.f && rate.mSpeed != 1.f)
-                        || rate.mPitch != 1.f)) {
+                if (mOffloadAudio && (rate.mSpeed != 1.f || rate.mPitch != 1.f)) {
                     int64_t currentPositionUs;
                     if (getCurrentPosition(&currentPositionUs) != OK) {
                         currentPositionUs = mPreviousSeekTimeUs;
@@ -1010,36 +1009,15 @@
                 err = mRenderer->setPlaybackSettings(rate);
             }
             if (err == OK) {
-                if (rate.mSpeed == 0.f) {
-                    onPause();
-                    notifyListener(mSrcId, MEDIA2_PAUSED, 0, 0);
-                    mPausedByClient = true;
-                    // save all other settings (using non-paused speed)
-                    // so we can restore them on start
-                    AudioPlaybackRate newRate = rate;
-                    newRate.mSpeed = mPlaybackSettings.mSpeed;
-                    mPlaybackSettings = newRate;
-                } else { /* rate.mSpeed != 0.f */
-                    mPlaybackSettings = rate;
-                    if (mStarted) {
-                        // do not resume yet if the source is still buffering
-                        if (!mPausedForBuffering) {
-                            onResume();
-                        }
-                    } else if (mPrepared) {
-                        onStart();
-                    }
+                mPlaybackSettings = rate;
 
-                    mPausedByClient = false;
+                if (mVideoDecoder != NULL) {
+                    sp<AMessage> params = new AMessage();
+                    params->setFloat("playback-speed", mPlaybackSettings.mSpeed);
+                    mVideoDecoder->setParameters(params);
                 }
             }
 
-            if (mVideoDecoder != NULL) {
-                sp<AMessage> params = new AMessage();
-                params->setFloat("playback-speed", mPlaybackSettings.mSpeed);
-                mVideoDecoder->setParameters(params);
-            }
-
             sp<AMessage> response = new AMessage;
             response->setInt32("err", err);
             response->postReply(replyID);
@@ -1059,9 +1037,6 @@
                 // get playback settings used by renderer, as it may be
                 // slightly off due to audiosink not taking small changes.
                 mPlaybackSettings = rate;
-                if (mPaused) {
-                    rate.mSpeed = 0.f;
-                }
             }
             sp<AMessage> response = new AMessage;
             if (err == OK) {
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
index d3be53a..b02e3f6 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
@@ -352,14 +352,6 @@
         // try to update position
         int64_t unused;
         getCurrentPosition(&unused);
-        Mutex::Autolock autoLock(mLock);
-        if (rate.mSpeed == 0.f && mState == STATE_RUNNING) {
-            mState = STATE_PAUSED;
-        } else if (rate.mSpeed != 0.f
-                && (mState == STATE_PAUSED
-                    || mState == STATE_PREPARED)) {
-            err = start_l();
-        }
     }
     return err;
 }
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
index a0bd900..021ddde 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
@@ -133,8 +133,7 @@
       mUseAudioCallback(false),
       mWakeLock(new JWakeLock()) {
     CHECK(mediaClock != NULL);
-    mPlaybackRate = mPlaybackSettings.mSpeed;
-    mMediaClock->setPlaybackRate(mPlaybackRate);
+    mMediaClock->setPlaybackRate(mPlaybackSettings.mSpeed);
 }
 
 NuPlayer2::Renderer::~Renderer() {
@@ -190,26 +189,20 @@
 }
 
 status_t NuPlayer2::Renderer::onConfigPlayback(const AudioPlaybackRate &rate /* sanitized */) {
-    if (rate.mSpeed == 0.f) {
-        onPause();
-        // don't call audiosink's setPlaybackRate if pausing, as pitch does not
-        // have to correspond to the any non-0 speed (e.g old speed). Keep
-        // settings nonetheless, using the old speed, in case audiosink changes.
-        AudioPlaybackRate newRate = rate;
-        newRate.mSpeed = mPlaybackSettings.mSpeed;
-        mPlaybackSettings = newRate;
-        return OK;
+    if (rate.mSpeed <= 0.f) {
+        ALOGW("playback rate cannot be %f", rate.mSpeed);
+        return BAD_VALUE;
     }
 
     if (mAudioSink != NULL && mAudioSink->ready()) {
         status_t err = mAudioSink->setPlaybackRate(rate);
         if (err != OK) {
+            ALOGW("failed to get playback rate from audio sink, err(%d)", err);
             return err;
         }
     }
     mPlaybackSettings = rate;
-    mPlaybackRate = rate.mSpeed;
-    mMediaClock->setPlaybackRate(mPlaybackRate);
+    mMediaClock->setPlaybackRate(mPlaybackSettings.mSpeed);
     return OK;
 }
 
@@ -236,9 +229,6 @@
             // get playback settings used by audiosink, as it may be
             // slightly off due to audiosink not taking small changes.
             mPlaybackSettings = *rate;
-            if (mPaused) {
-                rate->mSpeed = 0.f;
-            }
         }
         return err;
     }
@@ -560,8 +550,8 @@
                 int64_t delayUs =
                     mAudioSink->msecsPerFrame()
                         * numFramesPendingPlayout * 1000ll;
-                if (mPlaybackRate > 1.0f) {
-                    delayUs /= mPlaybackRate;
+                if (mPlaybackSettings.mSpeed > 1.0f) {
+                    delayUs /= mPlaybackSettings.mSpeed;
                 }
 
                 // Let's give it more data after about half that time
@@ -1773,7 +1763,7 @@
             mAudioSink->setPlaybackRate(mPlaybackSettings);
         }
 
-        mMediaClock->setPlaybackRate(mPlaybackRate);
+        mMediaClock->setPlaybackRate(mPlaybackSettings.mSpeed);
 
         if (!mAudioQueue.empty()) {
             postDrainAudioQueue_l();
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.h
index 62cf0d8..305af68 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.h
@@ -167,7 +167,6 @@
     int32_t mAudioEOSGeneration;
 
     const sp<MediaClock> mMediaClock;
-    float mPlaybackRate; // audio track rate
 
     AudioPlaybackRate mPlaybackSettings;
     AVSyncSettings mSyncSettings;
diff --git a/media/libnblog/Merger.cpp b/media/libnblog/Merger.cpp
index 5e6f79a..30f6fe3 100644
--- a/media/libnblog/Merger.cpp
+++ b/media/libnblog/Merger.cpp
@@ -167,12 +167,24 @@
             const double timeMs = it.payload<double>();
             data.warmupHist.add(timeMs);
         } break;
-        case EVENT_UNDERRUN:
+        case EVENT_UNDERRUN: {
+            const int64_t ts = it.payload<int64_t>();
             data.underruns++;
-            break;
-        case EVENT_OVERRUN:
+            data.snapshots.emplace_front(EVENT_UNDERRUN, ts);
+            // TODO have a data structure to automatically handle resizing
+            if (data.snapshots.size() > ReportPerformance::PerformanceData::kMaxSnapshotsToStore) {
+                data.snapshots.pop_back();
+            }
+        } break;
+        case EVENT_OVERRUN: {
+            const int64_t ts = it.payload<int64_t>();
             data.overruns++;
-            break;
+            data.snapshots.emplace_front(EVENT_UNDERRUN, ts);
+            // TODO have a data structure to automatically handle resizing
+            if (data.snapshots.size() > ReportPerformance::PerformanceData::kMaxSnapshotsToStore) {
+                data.snapshots.pop_back();
+            }
+        } break;
         case EVENT_RESERVED:
         case EVENT_UPPER_BOUND:
             ALOGW("warning: unexpected event %d", it->type);
@@ -216,7 +228,7 @@
 {
     // TODO: add a mutex around media.log dump
     // Options for dumpsys
-    bool pa = false, json = false, plots = false;
+    bool pa = false, json = false, plots = false, retro = false;
     for (const auto &arg : args) {
         if (arg == String16("--pa")) {
             pa = true;
@@ -224,6 +236,8 @@
             json = true;
         } else if (arg == String16("--plots")) {
             plots = true;
+        } else if (arg == String16("--retro")) {
+            retro = true;
         }
     }
     if (pa) {
@@ -235,6 +249,9 @@
     if (plots) {
         ReportPerformance::dumpPlots(fd, mThreadPerformanceData);
     }
+    if (retro) {
+        ReportPerformance::dumpRetro(fd, mThreadPerformanceData);
+    }
 }
 
 void MergeReader::handleAuthor(const AbstractEntry &entry, String8 *body)
diff --git a/media/libnblog/Reader.cpp b/media/libnblog/Reader.cpp
index f86bb99..dfad332 100644
--- a/media/libnblog/Reader.cpp
+++ b/media/libnblog/Reader.cpp
@@ -59,7 +59,7 @@
 // Copies content of a Reader FIFO into its Snapshot
 // The Snapshot has the same raw data, but represented as a sequence of entries
 // and an EntryIterator making it possible to process the data.
-std::unique_ptr<Snapshot> Reader::getSnapshot()
+std::unique_ptr<Snapshot> Reader::getSnapshot(bool flush)
 {
     if (mFifoReader == NULL) {
         return std::unique_ptr<Snapshot>(new Snapshot());
@@ -146,7 +146,9 @@
     }
 
     // advance fifo reader index to after last entry read.
-    mFifoReader->release(snapshot->mEnd - front);
+    if (flush) {
+        mFifoReader->release(snapshot->mEnd - front);
+    }
 
     snapshot->mLost = lost;
     return snapshot;
@@ -221,36 +223,48 @@
 void DumpReader::dump(int fd, size_t indent)
 {
     if (fd < 0) return;
-    std::unique_ptr<Snapshot> snapshot = getSnapshot();
+    std::unique_ptr<Snapshot> snapshot = getSnapshot(false /*flush*/);
     if (snapshot == nullptr) {
         return;
     }
     String8 timestamp, body;
 
     // TODO all logged types should have a printable format.
+    // TODO can we make the printing generic?
     for (EntryIterator it = snapshot->begin(); it != snapshot->end(); ++it) {
         switch (it->type) {
         case EVENT_FMT_START:
             it = handleFormat(FormatEntry(it), &timestamp, &body);
             break;
-        case EVENT_WORK_TIME: {
-            const int64_t monotonicNs = it.payload<int64_t>();
-            body.appendFormat("Thread cycle: %ld ns", (long)monotonicNs);
-        } break;
         case EVENT_LATENCY: {
             const double latencyMs = it.payload<double>();
-            body.appendFormat("latency: %.3f ms", latencyMs);
+            body.appendFormat("EVENT_LATENCY,%.3f", latencyMs);
+        } break;
+        case EVENT_OVERRUN: {
+            const int64_t ts = it.payload<int64_t>();
+            body.appendFormat("EVENT_OVERRUN,%lld", static_cast<long long>(ts));
+        } break;
+        case EVENT_THREAD_INFO: {
+            const thread_info_t info = it.payload<thread_info_t>();
+            body.appendFormat("EVENT_THREAD_INFO,%d,%s", static_cast<int>(info.id),
+                    threadTypeToString(info.type));
+        } break;
+        case EVENT_UNDERRUN: {
+            const int64_t ts = it.payload<int64_t>();
+            body.appendFormat("EVENT_UNDERRUN,%lld", static_cast<long long>(ts));
         } break;
         case EVENT_WARMUP_TIME: {
             const double timeMs = it.payload<double>();
-            body.appendFormat("warmup time: %.3f ms", timeMs);
+            body.appendFormat("EVENT_WARMUP_TIME,%.3f", timeMs);
         } break;
-        case EVENT_UNDERRUN:
-            body.appendFormat("underrun");
-            break;
-        case EVENT_OVERRUN:
-            body.appendFormat("overrun");
-            break;
+        case EVENT_WORK_TIME: {
+            const int64_t monotonicNs = it.payload<int64_t>();
+            body.appendFormat("EVENT_WORK_TIME,%lld", static_cast<long long>(monotonicNs));
+        } break;
+        case EVENT_THREAD_PARAMS: {
+            const thread_params_t params = it.payload<thread_params_t>();
+            body.appendFormat("EVENT_THREAD_PARAMS,%zu,%u", params.frameCount, params.sampleRate);
+        } break;
         case EVENT_FMT_END:
         case EVENT_RESERVED:
         case EVENT_UPPER_BOUND:
diff --git a/media/libnblog/ReportPerformance.cpp b/media/libnblog/ReportPerformance.cpp
index 7e40947..f632e40 100644
--- a/media/libnblog/ReportPerformance.cpp
+++ b/media/libnblog/ReportPerformance.cpp
@@ -113,6 +113,41 @@
     }
 }
 
+static std::string dumpRetroString(const PerformanceData& data, int64_t now)
+{
+    std::stringstream ss;
+    ss << NBLog::threadTypeToString(data.threadInfo.type) << "," << data.threadInfo.id << "\n";
+    for (const auto &item : data.snapshots) {
+        // TODO use an enum to string conversion method. One good idea:
+        // https://stackoverflow.com/a/238157
+        if (item.first == NBLog::EVENT_UNDERRUN) {
+            ss << "EVENT_UNDERRUN,";
+        } else if (item.first == NBLog::EVENT_OVERRUN) {
+            ss << "EVENT_OVERRUN,";
+        }
+        ss << now - item.second << "\n";
+    }
+    ss << "\n";
+    return ss.str();
+}
+
+void dumpRetro(int fd, const std::map<int, PerformanceData>& threadDataMap)
+{
+    if (fd < 0) {
+        return;
+    }
+
+    const nsecs_t now = systemTime();
+    for (const auto &item : threadDataMap) {
+        const ReportPerformance::PerformanceData& data = item.second;
+        if (data.snapshots.empty()) {
+            continue;
+        }
+        const std::string retroStr = dumpRetroString(data, now);
+        write(fd, retroStr.c_str(), retroStr.size());
+    }
+}
+
 bool sendToMediaMetrics(const PerformanceData& data)
 {
     // See documentation for these metrics here:
diff --git a/media/libnblog/include/media/nblog/PerformanceAnalysis.h b/media/libnblog/include/media/nblog/PerformanceAnalysis.h
index b1e09d7..d7c16b6 100644
--- a/media/libnblog/include/media/nblog/PerformanceAnalysis.h
+++ b/media/libnblog/include/media/nblog/PerformanceAnalysis.h
@@ -19,6 +19,7 @@
 
 #include <deque>
 #include <map>
+#include <string>
 #include <utility>
 #include <vector>
 
@@ -159,6 +160,8 @@
     Histogram latencyHist{kLatencyConfig};
     Histogram warmupHist{kWarmupConfig};
     int64_t underruns = 0;
+    static constexpr size_t kMaxSnapshotsToStore = 256;
+    std::deque<std::pair<NBLog::Event, int64_t /*timestamp*/>> snapshots;
     int64_t overruns = 0;
     nsecs_t active = 0;
     nsecs_t start{systemTime()};
diff --git a/media/libnblog/include/media/nblog/Reader.h b/media/libnblog/include/media/nblog/Reader.h
index bf1c321..2495e8c 100644
--- a/media/libnblog/include/media/nblog/Reader.h
+++ b/media/libnblog/include/media/nblog/Reader.h
@@ -51,7 +51,7 @@
     ~Reader() override;
 
     // get snapshot of readers fifo buffer, effectively consuming the buffer
-    std::unique_ptr<Snapshot> getSnapshot();
+    std::unique_ptr<Snapshot> getSnapshot(bool flush = true);
     bool     isIMemory(const sp<IMemory>& iMemory) const;
     const std::string &name() const { return mName; }
 
@@ -99,7 +99,7 @@
 private:
     Snapshot() = default;
     explicit Snapshot(size_t bufferSize) : mData(new uint8_t[bufferSize]) {}
-    friend std::unique_ptr<Snapshot> Reader::getSnapshot();
+    friend std::unique_ptr<Snapshot> Reader::getSnapshot(bool flush);
 
     uint8_t * const       mData = nullptr;
     size_t                mLost = 0;
diff --git a/media/libnblog/include/media/nblog/ReportPerformance.h b/media/libnblog/include/media/nblog/ReportPerformance.h
index caad14c..64a5701 100644
--- a/media/libnblog/include/media/nblog/ReportPerformance.h
+++ b/media/libnblog/include/media/nblog/ReportPerformance.h
@@ -32,6 +32,9 @@
 //Dumps performance data as visualized plots.
 void dumpPlots(int fd, const std::map<int, PerformanceData>& threadDataMap);
 
+// Dumps snapshots at important events in the past.
+void dumpRetro(int fd, const std::map<int, PerformanceData>& threadDataMap);
+
 // Send one thread's data to media metrics, if the performance data is nontrivial (i.e. not
 // all zero values). Return true if data was sent, false if there is nothing to write
 // or an error occurred while writing.
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 8e8c77c..e42d8d0 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -21,7 +21,6 @@
 #include <media/stagefright/NuMediaExtractor.h>
 
 #include "include/ESDS.h"
-#include "include/NuCachedSource2.h"
 
 #include <media/DataSource.h>
 #include <media/MediaSource.h>
@@ -207,10 +206,7 @@
 
 void NuMediaExtractor::disconnect() {
     if (mDataSource != NULL) {
-        // disconnect data source
-        if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
-            static_cast<NuCachedSource2 *>(mDataSource.get())->disconnect();
-        }
+        mDataSource->disconnect();
     }
 }
 
@@ -790,16 +786,13 @@
         int64_t *durationUs, bool *eos) const {
     Mutex::Autolock autoLock(mLock);
 
+    status_t finalStatus;
+    ssize_t cachedDataRemaining =
+        mDataSource->getAvailableSize(&finalStatus);
+
     int64_t bitrate;
-    if ((mDataSource->flags() & DataSource::kIsCachingDataSource)
+    if (cachedDataRemaining >= 0
             && getTotalBitrate(&bitrate)) {
-        sp<NuCachedSource2> cachedSource =
-            static_cast<NuCachedSource2 *>(mDataSource.get());
-
-        status_t finalStatus;
-        size_t cachedDataRemaining =
-            cachedSource->approxDataRemaining(&finalStatus);
-
         *durationUs = cachedDataRemaining * 8000000ll / bitrate;
         *eos = (finalStatus != OK);
         return true;
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index be01a7d..231d540 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -342,15 +342,15 @@
 
     for (size_t i = 0; i < matchingCodecs.size(); ++i) {
         const AString &componentName = matchingCodecs[i];
-        VideoFrameDecoder decoder(componentName, trackMeta, source);
-        if (decoder.init(timeUs, numFrames, option, colorFormat) == OK) {
+        sp<VideoFrameDecoder> decoder = new VideoFrameDecoder(componentName, trackMeta, source);
+        if (decoder->init(timeUs, numFrames, option, colorFormat) == OK) {
             if (outFrame != NULL) {
-                *outFrame = decoder.extractFrame();
+                *outFrame = decoder->extractFrame();
                 if (*outFrame != NULL) {
                     return OK;
                 }
             } else if (outFrames != NULL) {
-                status_t err = decoder.extractFrames(outFrames);
+                status_t err = decoder->extractFrames(outFrames);
                 if (err == OK) {
                     return OK;
                 }
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
index 8912f8a..d534f64 100644
--- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
@@ -548,11 +548,21 @@
         // Make sure that the next buffer output does not still
         // depend on fragments from the last one decoded.
 
+        mInputBufferCount = 0;
         mNumFramesOutput = 0;
+        if (mState != NULL) {
+            vorbis_dsp_clear(mState);
+            delete mState;
+            mState = NULL;
+        }
+        if (mVi != NULL) {
+            vorbis_info_clear(mVi);
+            delete mVi;
+            mVi = NULL;
+        }
         mSawInputEos = false;
         mSignalledOutputEos = false;
         mNumFramesLeftOnPage = -1;
-        vorbis_dsp_restart(mState);
     }
 }
 
diff --git a/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp b/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp
index 06b15b3..f352fba 100644
--- a/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp
+++ b/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp
@@ -79,7 +79,7 @@
 
 static const OMX_U32 kSupportedProfiles[] = {
     OMX_AUDIO_AACObjectLC, OMX_AUDIO_AACObjectHE,  OMX_AUDIO_AACObjectHE_PS,
-    OMX_AUDIO_AACObjectLD, OMX_AUDIO_AACObjectELD,
+    OMX_AUDIO_AACObjectLD, OMX_AUDIO_AACObjectELD, OMX_AUDIO_AACObjectXHE
 };
 
 SoftXAAC::SoftXAAC(const char* name, const OMX_CALLBACKTYPE* callbacks, OMX_PTR appData,
diff --git a/media/libstagefright/include/NuCachedSource2.h b/media/libstagefright/include/NuCachedSource2.h
index f439a1c..f4aab25 100644
--- a/media/libstagefright/include/NuCachedSource2.h
+++ b/media/libstagefright/include/NuCachedSource2.h
@@ -51,6 +51,10 @@
         return mName;
     }
 
+    ssize_t getAvailableSize(status_t *finalStatus) {
+        return approxDataRemaining(finalStatus);
+    }
+
     ////////////////////////////////////////////////////////////////////////////
 
     size_t cachedSize();
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 6e65ac0..62fd5f7 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -746,7 +746,7 @@
         output.afFrameCount = thread->frameCount();
         output.afSampleRate = thread->sampleRate();
         output.afLatencyMs = thread->latency();
-        output.trackId = track->id();
+        output.trackId = track == nullptr ? -1 : track->id();
 
         // move effect chain to this output thread if an effect on same session was waiting
         // for a track to be created
@@ -2500,7 +2500,9 @@
         if (recordThread != 0) {
             ALOGV("closeInput() %d", input);
 
+#if 0
             dumpToThreadLog_l(recordThread);
+#endif
 
             // If we still have effect chains, it means that a client still holds a handle
             // on at least one effect. We must either move the chain to an existing thread with the
@@ -2544,7 +2546,9 @@
             if (mmapThread == 0) {
                 return BAD_VALUE;
             }
+#if 0
             dumpToThreadLog_l(mmapThread);
+#endif
             mMmapThreads.removeItem(input);
         }
         const sp<AudioIoDescriptor> ioDesc = new AudioIoDescriptor();
diff --git a/services/audioflinger/FastThread.cpp b/services/audioflinger/FastThread.cpp
index 01b0432..04b32c2 100644
--- a/services/audioflinger/FastThread.cpp
+++ b/services/audioflinger/FastThread.cpp
@@ -66,8 +66,6 @@
     /* mMeasuredWarmupTs({0, 0}), */
     mWarmupCycles(0),
     mWarmupConsecutiveInRangeCycles(0),
-    mDummyNBLogWriter(new NBLog::Writer()),
-    mNBLogWriter(mDummyNBLogWriter.get()),
     mTimestampStatus(INVALID_OPERATION),
 
     mCommand(FastThreadState::INITIAL),
@@ -124,10 +122,9 @@
 
             // As soon as possible of learning of a new dump area, start using it
             mDumpState = next->mDumpState != NULL ? next->mDumpState : mDummyDumpState;
-            mNBLogWriter = next->mNBLogWriter != NULL ?
+            tlNBLogWriter = next->mNBLogWriter != NULL ?
                     next->mNBLogWriter : mDummyNBLogWriter.get();
-            setNBLogWriter(mNBLogWriter);   // FastMixer informs its AudioMixer, FastCapture ignores
-            tlNBLogWriter = mNBLogWriter;
+            setNBLogWriter(tlNBLogWriter); // FastMixer informs its AudioMixer, FastCapture ignores
 
             // 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.
diff --git a/services/audioflinger/FastThread.h b/services/audioflinger/FastThread.h
index bbb1d22..3f6b206 100644
--- a/services/audioflinger/FastThread.h
+++ b/services/audioflinger/FastThread.h
@@ -81,9 +81,7 @@
     struct timespec   mMeasuredWarmupTs;  // how long did it take for warmup to complete
     uint32_t          mWarmupCycles;  // counter of number of loop cycles during warmup phase
     uint32_t          mWarmupConsecutiveInRangeCycles;    // number of consecutive cycles in range
-    sp<NBLog::Writer> mDummyNBLogWriter;
-    NBLog::Writer*    mNBLogWriter;   // always non-nullptr: real NBLog::Writer* or
-                                      // mDummyNBLogWriter.get()
+    const sp<NBLog::Writer> mDummyNBLogWriter{new NBLog::Writer()};
     status_t          mTimestampStatus;
 
     FastThreadState::Command mCommand;
diff --git a/services/audiopolicy/common/managerdefinitions/include/Serializer.h b/services/audiopolicy/common/managerdefinitions/include/Serializer.h
index 29de848..48c4147 100644
--- a/services/audiopolicy/common/managerdefinitions/include/Serializer.h
+++ b/services/audiopolicy/common/managerdefinitions/include/Serializer.h
@@ -17,223 +17,9 @@
 #pragma once
 
 #include "AudioPolicyConfig.h"
-#include <utils/StrongPointer.h>
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-#include <string>
-#include <sstream>
-#include <fstream>
-
-struct _xmlNode;
-struct _xmlDoc;
 
 namespace android {
 
-struct AudioGainTraits
-{
-    static const char *const tag;
-    static const char *const collectionTag;
-
-    struct Attributes
-    {
-        static const char mode[]; /**< gain modes supported, e.g. AUDIO_GAIN_MODE_CHANNELS. */
-        /** controlled channels, needed if mode AUDIO_GAIN_MODE_CHANNELS. */
-        static const char channelMask[];
-        static const char minValueMB[]; /**< min value in millibel. */
-        static const char maxValueMB[]; /**< max value in millibel. */
-        static const char defaultValueMB[]; /**< default value in millibel. */
-        static const char stepValueMB[]; /**< step value in millibel. */
-        static const char minRampMs[]; /**< needed if mode AUDIO_GAIN_MODE_RAMP. */
-        static const char maxRampMs[]; /**< .needed if mode AUDIO_GAIN_MODE_RAMP */
-    };
-
-    typedef AudioGain Element;
-    typedef sp<Element> PtrElement;
-    typedef AudioGainCollection Collection;
-    typedef void *PtrSerializingCtx;
-
-    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
-                                PtrSerializingCtx serializingContext);
-
-    // Gain has no child
-};
-
-// A profile section contains a name,  one audio format and the list of supported sampling rates
-// and channel masks for this format
-struct AudioProfileTraits
-{
-    static const char *const tag;
-    static const char *const collectionTag;
-
-    struct Attributes
-    {
-        static const char name[];
-        static const char samplingRates[];
-        static const char format[];
-        static const char channelMasks[];
-    };
-
-    typedef AudioProfile Element;
-    typedef sp<AudioProfile> PtrElement;
-    typedef AudioProfileVector Collection;
-    typedef void *PtrSerializingCtx;
-
-    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
-                                PtrSerializingCtx serializingContext);
-};
-
-struct MixPortTraits
-{
-    static const char *const tag;
-    static const char *const collectionTag;
-
-    struct Attributes
-    {
-        static const char name[];
-        static const char role[];
-        static const char flags[];
-        static const char maxOpenCount[];
-        static const char maxActiveCount[];
-    };
-
-    typedef IOProfile Element;
-    typedef sp<Element> PtrElement;
-    typedef IOProfileCollection Collection;
-    typedef void *PtrSerializingCtx;
-
-    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
-                                PtrSerializingCtx serializingContext);
-
-    // Children are: GainTraits
-};
-
-struct DevicePortTraits
-{
-    static const char *const tag;
-    static const char *const collectionTag;
-
-    struct Attributes
-    {
-        static const char tagName[]; /**<  <device tag name>: any string without space. */
-        static const char type[]; /**< <device type>. */
-        static const char role[]; /**< <device role: sink or source>. */
-        static const char roleSource[]; /**< <attribute role source value>. */
-        static const char address[]; /**< optional: device address, char string less than 64. */
-    };
-    typedef DeviceDescriptor Element;
-    typedef sp<DeviceDescriptor> PtrElement;
-    typedef DeviceVector Collection;
-    typedef void *PtrSerializingCtx;
-
-    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
-                                PtrSerializingCtx serializingContext);
-    // Children are: GainTraits (optionnal)
-};
-
-struct RouteTraits
-{
-    static const char *const tag;
-    static const char *const collectionTag;
-
-    struct Attributes
-    {
-        static const char type[]; /**< <route type>: mix or mux. */
-        static const char typeMix[]; /**< type attribute mix value. */
-        static const char sink[]; /**< <sink: involved in this route>. */
-        static const char sources[]; /**< sources: all source that can be involved in this route. */
-    };
-    typedef AudioRoute Element;
-    typedef sp<AudioRoute> PtrElement;
-    typedef AudioRouteVector Collection;
-    typedef HwModule *PtrSerializingCtx;
-
-    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
-                                PtrSerializingCtx ctx);
-};
-
-struct ModuleTraits
-{
-    static const char *const tag;
-    static const char *const collectionTag;
-
-    static const char *const childAttachedDevicesTag;
-    static const char *const childAttachedDeviceTag;
-    static const char *const childDefaultOutputDeviceTag;
-
-    struct Attributes
-    {
-        static const char name[];
-        static const char version[];
-    };
-
-    typedef HwModule Element;
-    typedef sp<Element> PtrElement;
-    typedef HwModuleCollection Collection;
-    typedef AudioPolicyConfig *PtrSerializingCtx;
-
-    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
-                                PtrSerializingCtx serializingContext);
-
-    // Children are: mixPortTraits, devicePortTraits and routeTraits
-    // Need to call deserialize on each child
-};
-
-struct GlobalConfigTraits
-{
-    static const char *const tag;
-
-    struct Attributes
-    {
-        static const char speakerDrcEnabled[];
-    };
-
-    static status_t deserialize(const _xmlNode *root, AudioPolicyConfig &config);
-};
-
-struct VolumeTraits
-{
-    static const char *const tag;
-    static const char *const collectionTag;
-    static const char *const volumePointTag;
-
-    struct Attributes
-    {
-        static const char stream[];
-        static const char deviceCategory[];
-        static const char reference[];
-    };
-
-    typedef VolumeCurve Element;
-    typedef sp<VolumeCurve> PtrElement;
-    typedef VolumeCurvesCollection Collection;
-    typedef void *PtrSerializingCtx;
-
-    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
-                                PtrSerializingCtx serializingContext);
-
-    // No Child
-};
-
-class PolicySerializer
-{
-private:
-    static const char *const rootName;
-
-    static const char *const versionAttribute;
-    static const uint32_t gMajor; /**< the major number of the policy xml format version. */
-    static const uint32_t gMinor; /**< the minor number of the policy xml format version. */
-
-public:
-    PolicySerializer();
-    status_t deserialize(const char *str, AudioPolicyConfig &config);
-
-private:
-    typedef AudioPolicyConfig Element;
-
-    std::string mRootElementName;
-    std::string mVersion;
-
-    // Children are: ModulesTraits, VolumeTraits
-};
+status_t deserializeAudioPolicyFile(const char *fileName, AudioPolicyConfig *config);
 
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index 8008a7c..e062e4e 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -17,164 +17,356 @@
 #define LOG_TAG "APM::Serializer"
 //#define LOG_NDEBUG 0
 
-#include "Serializer.h"
-#include <media/convert.h>
-#include "TypeConverter.h"
+#include <memory>
+#include <string>
+
 #include <libxml/parser.h>
 #include <libxml/xinclude.h>
-#include <string>
-#include <sstream>
-#include <istream>
-
-using std::string;
+#include <media/convert.h>
+#include <utils/Log.h>
+#include <utils/StrongPointer.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include "Serializer.h"
+#include "TypeConverter.h"
 
 namespace android {
 
-string getXmlAttribute(const xmlNode *cur, const char *attribute)
-{
-    xmlChar *xmlValue = xmlGetProp(cur, (const xmlChar*)attribute);
-    if (xmlValue == NULL) {
-        return "";
-    }
-    string value((const char*)xmlValue);
-    xmlFree(xmlValue);
-    return value;
-}
+namespace {
 
 using utilities::convertTo;
 
-const char *const PolicySerializer::rootName = "audioPolicyConfiguration";
-const char *const PolicySerializer::versionAttribute = "version";
-const uint32_t PolicySerializer::gMajor = 1;
-const uint32_t PolicySerializer::gMinor = 0;
-static const char *const gReferenceElementName = "reference";
-static const char *const gReferenceAttributeName = "name";
+template<typename E, typename C>
+struct BaseSerializerTraits {
+    typedef E Element;
+    typedef sp<E> PtrElement;
+    typedef C Collection;
+    typedef void* PtrSerializingCtx;
+};
 
-template <class Trait>
-static void getReference(const _xmlNode *root, const _xmlNode *&refNode, const string &refName)
+struct AudioGainTraits : public BaseSerializerTraits<AudioGain, AudioGainCollection>
 {
-    const _xmlNode *col = root;
-    while (col != NULL) {
-        if (!xmlStrcmp(col->name, (const xmlChar *)Trait::collectionTag)) {
-            const xmlNode *cur = col->children;
-            while (cur != NULL) {
-                if ((!xmlStrcmp(cur->name, (const xmlChar *)gReferenceElementName))) {
-                    string name = getXmlAttribute(cur, gReferenceAttributeName);
-                    if (refName == name) {
-                        refNode = cur;
-                        return;
-                    }
-                }
-                cur = cur->next;
-            }
-        }
-        col = col->next;
+    static constexpr const char *tag = "gain";
+    static constexpr const char *collectionTag = "gains";
+
+    struct Attributes
+    {
+        /** gain modes supported, e.g. AUDIO_GAIN_MODE_CHANNELS. */
+        static constexpr const char *mode = "mode";
+        /** controlled channels, needed if mode AUDIO_GAIN_MODE_CHANNELS. */
+        static constexpr const char *channelMask = "channel_mask";
+        static constexpr const char *minValueMB = "minValueMB"; /**< min value in millibel. */
+        static constexpr const char *maxValueMB = "maxValueMB"; /**< max value in millibel. */
+        /** default value in millibel. */
+        static constexpr const char *defaultValueMB = "defaultValueMB";
+        static constexpr const char *stepValueMB = "stepValueMB"; /**< step value in millibel. */
+        /** needed if mode AUDIO_GAIN_MODE_RAMP. */
+        static constexpr const char *minRampMs = "minRampMs";
+        /** needed if mode AUDIO_GAIN_MODE_RAMP. */
+        static constexpr const char *maxRampMs = "maxRampMs";
+    };
+
+    static status_t deserialize(xmlDoc *doc, const xmlNode *root, PtrElement *element,
+                                PtrSerializingCtx serializingContext);
+    // No children
+};
+
+// A profile section contains a name,  one audio format and the list of supported sampling rates
+// and channel masks for this format
+struct AudioProfileTraits : public BaseSerializerTraits<AudioProfile, AudioProfileVector>
+{
+    static constexpr const char *tag = "profile";
+    static constexpr const char *collectionTag = "profiles";
+
+    struct Attributes
+    {
+        static constexpr const char *samplingRates = "samplingRates";
+        static constexpr const char *format = "format";
+        static constexpr const char *channelMasks = "channelMasks";
+    };
+
+    static status_t deserialize(xmlDoc *doc, const xmlNode *root, PtrElement *element,
+                                PtrSerializingCtx serializingContext);
+};
+
+struct MixPortTraits : public BaseSerializerTraits<IOProfile, IOProfileCollection>
+{
+    static constexpr const char *tag = "mixPort";
+    static constexpr const char *collectionTag = "mixPorts";
+
+    struct Attributes
+    {
+        static constexpr const char *name = "name";
+        static constexpr const char *role = "role";
+        static constexpr const char *roleSource = "source"; /**< <attribute role source value>. */
+        static constexpr const char *flags = "flags";
+        static constexpr const char *maxOpenCount = "maxOpenCount";
+        static constexpr const char *maxActiveCount = "maxActiveCount";
+    };
+
+    static status_t deserialize(xmlDoc *doc, const xmlNode *root, PtrElement *element,
+                                PtrSerializingCtx serializingContext);
+    // Children: GainTraits
+};
+
+struct DevicePortTraits : public BaseSerializerTraits<DeviceDescriptor, DeviceVector>
+{
+    static constexpr const char *tag = "devicePort";
+    static constexpr const char *collectionTag = "devicePorts";
+
+    struct Attributes
+    {
+        /**  <device tag name>: any string without space. */
+        static constexpr const char *tagName = "tagName";
+        static constexpr const char *type = "type"; /**< <device type>. */
+        static constexpr const char *role = "role"; /**< <device role: sink or source>. */
+        static constexpr const char *roleSource = "source"; /**< <attribute role source value>. */
+        /** optional: device address, char string less than 64. */
+        static constexpr const char *address = "address";
+    };
+
+    static status_t deserialize(xmlDoc *doc, const xmlNode *root, PtrElement *element,
+                                PtrSerializingCtx serializingContext);
+    // Children: GainTraits (optional)
+};
+
+struct RouteTraits : public BaseSerializerTraits<AudioRoute, AudioRouteVector>
+{
+    static constexpr const char *tag = "route";
+    static constexpr const char *collectionTag = "routes";
+
+    struct Attributes
+    {
+        static constexpr const char *type = "type"; /**< <route type>: mix or mux. */
+        static constexpr const char *typeMix = "mix"; /**< type attribute mix value. */
+        static constexpr const char *sink = "sink"; /**< <sink: involved in this route>. */
+        /** sources: all source that can be involved in this route. */
+        static constexpr const char *sources = "sources";
+    };
+
+    typedef HwModule *PtrSerializingCtx;
+
+    static status_t deserialize(xmlDoc *doc, const xmlNode *root, PtrElement *element,
+                                PtrSerializingCtx ctx);
+};
+
+struct ModuleTraits : public BaseSerializerTraits<HwModule, HwModuleCollection>
+{
+    static constexpr const char *tag = "module";
+    static constexpr const char *collectionTag = "modules";
+
+    static constexpr const char *childAttachedDevicesTag = "attachedDevices";
+    static constexpr const char *childAttachedDeviceTag = "item";
+    static constexpr const char *childDefaultOutputDeviceTag = "defaultOutputDevice";
+
+    struct Attributes
+    {
+        static constexpr const char *name = "name";
+        static constexpr const char *version = "halVersion";
+    };
+
+    typedef AudioPolicyConfig *PtrSerializingCtx;
+
+    static status_t deserialize(xmlDoc *doc, const xmlNode *root, PtrElement *element,
+                                PtrSerializingCtx serializingContext);
+
+    // Children: mixPortTraits, devicePortTraits, and routeTraits
+    // Need to call deserialize on each child
+};
+
+struct GlobalConfigTraits
+{
+    static constexpr const char *tag = "globalConfiguration";
+
+    struct Attributes
+    {
+        static constexpr const char *speakerDrcEnabled = "speaker_drc_enabled";
+    };
+
+    static status_t deserialize(const xmlNode *root, AudioPolicyConfig *config);
+};
+
+struct VolumeTraits : public BaseSerializerTraits<VolumeCurve, VolumeCurvesCollection>
+{
+    static constexpr const char *tag = "volume";
+    static constexpr const char *collectionTag = "volumes";
+    static constexpr const char *volumePointTag = "point";
+    static constexpr const char *referenceTag = "reference";
+
+    struct Attributes
+    {
+        static constexpr const char *stream = "stream";
+        static constexpr const char *deviceCategory = "deviceCategory";
+        static constexpr const char *reference = "ref";
+        static constexpr const char *referenceName = "name";
+    };
+
+    static status_t deserialize(xmlDoc *doc, const xmlNode *root, PtrElement *element,
+                                PtrSerializingCtx serializingContext);
+    // No Children
+};
+
+class PolicySerializer
+{
+public:
+    PolicySerializer() : mVersion{std::to_string(gMajor) + "." + std::to_string(gMinor)}
+    {
+        ALOGV("%s: Version=%s Root=%s", __func__, mVersion.c_str(), rootName);
     }
-    return;
+    status_t deserialize(const char *str, AudioPolicyConfig *config);
+
+private:
+    static constexpr const char *rootName = "audioPolicyConfiguration";
+    static constexpr const char *versionAttribute = "version";
+    static constexpr uint32_t gMajor = 1; /**< the major number of the policy xml format version. */
+    static constexpr uint32_t gMinor = 0; /**< the minor number of the policy xml format version. */
+
+    typedef AudioPolicyConfig Element;
+
+    const std::string mVersion;
+
+    // Children: ModulesTraits, VolumeTraits
+};
+
+template <class T>
+constexpr void (*xmlDeleter)(T* t);
+template <>
+constexpr auto xmlDeleter<xmlDoc> = xmlFreeDoc;
+// http://b/111067277 - Add back constexpr when we switch to C++17.
+template <>
+auto xmlDeleter<xmlChar> = [](xmlChar *s) { xmlFree(s); };
+
+/** @return a unique_ptr with the correct deleter for the libxml2 object. */
+template <class T>
+constexpr auto make_xmlUnique(T *t) {
+    // Wrap deleter in lambda to enable empty base optimization
+    auto deleter = [](T *t) { xmlDeleter<T>(t); };
+    return std::unique_ptr<T, decltype(deleter)>{t, deleter};
+}
+
+std::string getXmlAttribute(const xmlNode *cur, const char *attribute)
+{
+    auto xmlValue = make_xmlUnique(xmlGetProp(cur, reinterpret_cast<const xmlChar*>(attribute)));
+    if (xmlValue == nullptr) {
+        return "";
+    }
+    std::string value(reinterpret_cast<const char*>(xmlValue.get()));
+    return value;
 }
 
 template <class Trait>
-static status_t deserializeCollection(_xmlDoc *doc, const _xmlNode *cur,
-                                      typename Trait::Collection &collection,
-                                      typename Trait::PtrSerializingCtx serializingContext)
+const xmlNode* getReference(const xmlNode *cur, const std::string &refName)
 {
-    const xmlNode *root = cur->xmlChildrenNode;
-    while (root != NULL) {
-        if (xmlStrcmp(root->name, (const xmlChar *)Trait::collectionTag) &&
-                xmlStrcmp(root->name, (const xmlChar *)Trait::tag)) {
-            root = root->next;
+    while (cur != NULL) {
+        if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(Trait::collectionTag))) {
+            const xmlNode *child = cur->children;
+            while (child != NULL) {
+                if ((!xmlStrcmp(child->name,
+                                        reinterpret_cast<const xmlChar*>(Trait::referenceTag)))) {
+                    std::string name = getXmlAttribute(child, Trait::Attributes::referenceName);
+                    if (refName == name) {
+                        return child;
+                    }
+                }
+                child = child->next;
+            }
+        }
+        cur = cur->next;
+    }
+    return NULL;
+}
+
+template <class Trait>
+status_t deserializeCollection(xmlDoc *doc, const xmlNode *cur,
+        typename Trait::Collection *collection,
+        typename Trait::PtrSerializingCtx serializingContext)
+{
+    cur = cur->xmlChildrenNode;
+    while (cur != NULL) {
+        if (xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(Trait::collectionTag)) &&
+                xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(Trait::tag))) {
+            cur = cur->next;
             continue;
         }
-        const xmlNode *child = root;
-        if (!xmlStrcmp(child->name, (const xmlChar *)Trait::collectionTag)) {
+        const xmlNode *child = cur;
+        if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>(Trait::collectionTag))) {
             child = child->xmlChildrenNode;
         }
         while (child != NULL) {
-            if (!xmlStrcmp(child->name, (const xmlChar *)Trait::tag)) {
+            if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>(Trait::tag))) {
                 typename Trait::PtrElement element;
-                status_t status = Trait::deserialize(doc, child, element, serializingContext);
+                status_t status = Trait::deserialize(doc, child, &element, serializingContext);
                 if (status != NO_ERROR) {
                     return status;
                 }
-                if (collection.add(element) < 0) {
-                    ALOGE("%s: could not add element to %s collection", __FUNCTION__,
+                if (collection->add(element) < 0) {
+                    ALOGE("%s: could not add element to %s collection", __func__,
                           Trait::collectionTag);
+                    return BAD_VALUE;
                 }
             }
             child = child->next;
         }
-        if (!xmlStrcmp(root->name, (const xmlChar *)Trait::tag)) {
+        if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(Trait::tag))) {
             return NO_ERROR;
         }
-        root = root->next;
+        cur = cur->next;
     }
     return NO_ERROR;
 }
 
-const char *const AudioGainTraits::tag = "gain";
-const char *const AudioGainTraits::collectionTag = "gains";
-
-const char AudioGainTraits::Attributes::mode[] = "mode";
-const char AudioGainTraits::Attributes::channelMask[] = "channel_mask";
-const char AudioGainTraits::Attributes::minValueMB[] = "minValueMB";
-const char AudioGainTraits::Attributes::maxValueMB[] = "maxValueMB";
-const char AudioGainTraits::Attributes::defaultValueMB[] = "defaultValueMB";
-const char AudioGainTraits::Attributes::stepValueMB[] = "stepValueMB";
-const char AudioGainTraits::Attributes::minRampMs[] = "minRampMs";
-const char AudioGainTraits::Attributes::maxRampMs[] = "maxRampMs";
-
-status_t AudioGainTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *root, PtrElement &gain,
+status_t AudioGainTraits::deserialize(xmlDoc */*doc*/, const xmlNode *root, PtrElement *element,
                                       PtrSerializingCtx /*serializingContext*/)
 {
     static uint32_t index = 0;
-    gain = new Element(index++, true);
+    PtrElement &gain = *element = new Element(index++, true);
 
-    string mode = getXmlAttribute(root, Attributes::mode);
+    std::string mode = getXmlAttribute(root, Attributes::mode);
     if (!mode.empty()) {
         gain->setMode(GainModeConverter::maskFromString(mode));
     }
 
-    string channelsLiteral = getXmlAttribute(root, Attributes::channelMask);
+    std::string channelsLiteral = getXmlAttribute(root, Attributes::channelMask);
     if (!channelsLiteral.empty()) {
         gain->setChannelMask(channelMaskFromString(channelsLiteral));
     }
 
-    string minValueMBLiteral = getXmlAttribute(root, Attributes::minValueMB);
+    std::string minValueMBLiteral = getXmlAttribute(root, Attributes::minValueMB);
     int32_t minValueMB;
     if (!minValueMBLiteral.empty() && convertTo(minValueMBLiteral, minValueMB)) {
         gain->setMinValueInMb(minValueMB);
     }
 
-    string maxValueMBLiteral = getXmlAttribute(root, Attributes::maxValueMB);
+    std::string maxValueMBLiteral = getXmlAttribute(root, Attributes::maxValueMB);
     int32_t maxValueMB;
     if (!maxValueMBLiteral.empty() && convertTo(maxValueMBLiteral, maxValueMB)) {
         gain->setMaxValueInMb(maxValueMB);
     }
 
-    string defaultValueMBLiteral = getXmlAttribute(root, Attributes::defaultValueMB);
+    std::string defaultValueMBLiteral = getXmlAttribute(root, Attributes::defaultValueMB);
     int32_t defaultValueMB;
     if (!defaultValueMBLiteral.empty() && convertTo(defaultValueMBLiteral, defaultValueMB)) {
         gain->setDefaultValueInMb(defaultValueMB);
     }
 
-    string stepValueMBLiteral = getXmlAttribute(root, Attributes::stepValueMB);
+    std::string stepValueMBLiteral = getXmlAttribute(root, Attributes::stepValueMB);
     uint32_t stepValueMB;
     if (!stepValueMBLiteral.empty() && convertTo(stepValueMBLiteral, stepValueMB)) {
         gain->setStepValueInMb(stepValueMB);
     }
 
-    string minRampMsLiteral = getXmlAttribute(root, Attributes::minRampMs);
+    std::string minRampMsLiteral = getXmlAttribute(root, Attributes::minRampMs);
     uint32_t minRampMs;
     if (!minRampMsLiteral.empty() && convertTo(minRampMsLiteral, minRampMs)) {
         gain->setMinRampInMs(minRampMs);
     }
 
-    string maxRampMsLiteral = getXmlAttribute(root, Attributes::maxRampMs);
+    std::string maxRampMsLiteral = getXmlAttribute(root, Attributes::maxRampMs);
     uint32_t maxRampMs;
     if (!maxRampMsLiteral.empty() && convertTo(maxRampMsLiteral, maxRampMs)) {
         gain->setMaxRampInMs(maxRampMs);
     }
-    ALOGV("%s: adding new gain mode %08x channel mask %08x min mB %d max mB %d", __FUNCTION__,
+    ALOGV("%s: adding new gain mode %08x channel mask %08x min mB %d max mB %d", __func__,
           gain->getMode(), gain->getChannelMask(), gain->getMinValueInMb(),
           gain->getMaxValueInMb());
 
@@ -184,24 +376,16 @@
     return NO_ERROR;
 }
 
-const char *const AudioProfileTraits::collectionTag = "profiles";
-const char *const AudioProfileTraits::tag = "profile";
-
-const char AudioProfileTraits::Attributes::name[] = "name";
-const char AudioProfileTraits::Attributes::samplingRates[] = "samplingRates";
-const char AudioProfileTraits::Attributes::format[] = "format";
-const char AudioProfileTraits::Attributes::channelMasks[] = "channelMasks";
-
-status_t AudioProfileTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *root, PtrElement &profile,
+status_t AudioProfileTraits::deserialize(xmlDoc */*doc*/, const xmlNode *root, PtrElement *element,
                                          PtrSerializingCtx /*serializingContext*/)
 {
-    string samplingRates = getXmlAttribute(root, Attributes::samplingRates);
-    string format = getXmlAttribute(root, Attributes::format);
-    string channels = getXmlAttribute(root, Attributes::channelMasks);
+    std::string samplingRates = getXmlAttribute(root, Attributes::samplingRates);
+    std::string format = getXmlAttribute(root, Attributes::format);
+    std::string channels = getXmlAttribute(root, Attributes::channelMasks);
 
-    profile = new Element(formatFromString(format, gDynamicFormat),
-                          channelMasksFromString(channels, ","),
-                          samplingRatesFromString(samplingRates, ","));
+    PtrElement &profile = *element = new Element(formatFromString(format, gDynamicFormat),
+            channelMasksFromString(channels, ","),
+            samplingRatesFromString(samplingRates, ","));
 
     profile->setDynamicFormat(profile->getFormat() == gDynamicFormat);
     profile->setDynamicChannels(profile->getChannels().isEmpty());
@@ -210,43 +394,37 @@
     return NO_ERROR;
 }
 
-
-const char *const MixPortTraits::collectionTag = "mixPorts";
-const char *const MixPortTraits::tag = "mixPort";
-
-const char MixPortTraits::Attributes::name[] = "name";
-const char MixPortTraits::Attributes::role[] = "role";
-const char MixPortTraits::Attributes::flags[] = "flags";
-const char MixPortTraits::Attributes::maxOpenCount[] = "maxOpenCount";
-const char MixPortTraits::Attributes::maxActiveCount[] = "maxActiveCount";
-
-status_t MixPortTraits::deserialize(_xmlDoc *doc, const _xmlNode *child, PtrElement &mixPort,
+status_t MixPortTraits::deserialize(xmlDoc *doc, const xmlNode *child, PtrElement *element,
                                     PtrSerializingCtx /*serializingContext*/)
 {
-    string name = getXmlAttribute(child, Attributes::name);
+    std::string name = getXmlAttribute(child, Attributes::name);
     if (name.empty()) {
-        ALOGE("%s: No %s found", __FUNCTION__, Attributes::name);
+        ALOGE("%s: No %s found", __func__, Attributes::name);
         return BAD_VALUE;
     }
-    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::name, name.c_str());
-    string role = getXmlAttribute(child, Attributes::role);
+    ALOGV("%s: %s %s=%s", __func__, tag, Attributes::name, name.c_str());
+    std::string role = getXmlAttribute(child, Attributes::role);
     if (role.empty()) {
-        ALOGE("%s: No %s found", __FUNCTION__, Attributes::role);
+        ALOGE("%s: No %s found", __func__, Attributes::role);
         return BAD_VALUE;
     }
-    ALOGV("%s: Role=%s", __FUNCTION__, role.c_str());
-    audio_port_role_t portRole = role == "source" ? AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
+    ALOGV("%s: Role=%s", __func__, role.c_str());
+    audio_port_role_t portRole = (role == Attributes::roleSource) ?
+            AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
 
-    mixPort = new Element(String8(name.c_str()), portRole);
+    PtrElement &mixPort = *element = new Element(String8(name.c_str()), portRole);
 
     AudioProfileTraits::Collection profiles;
-    deserializeCollection<AudioProfileTraits>(doc, child, profiles, NULL);
+    status_t status = deserializeCollection<AudioProfileTraits>(doc, child, &profiles, NULL);
+    if (status != NO_ERROR) {
+        return status;
+    }
     if (profiles.isEmpty()) {
         profiles.add(AudioProfile::createFullDynamic());
     }
     mixPort->setAudioProfiles(profiles);
 
-    string flags = getXmlAttribute(child, Attributes::flags);
+    std::string flags = getXmlAttribute(child, Attributes::flags);
     if (!flags.empty()) {
         // Source role
         if (portRole == AUDIO_PORT_ROLE_SOURCE) {
@@ -256,52 +434,46 @@
             mixPort->setFlags(InputFlagConverter::maskFromString(flags));
         }
     }
-    string maxOpenCount = getXmlAttribute(child, Attributes::maxOpenCount);
+    std::string maxOpenCount = getXmlAttribute(child, Attributes::maxOpenCount);
     if (!maxOpenCount.empty()) {
         convertTo(maxOpenCount, mixPort->maxOpenCount);
     }
-    string maxActiveCount = getXmlAttribute(child, Attributes::maxActiveCount);
+    std::string maxActiveCount = getXmlAttribute(child, Attributes::maxActiveCount);
     if (!maxActiveCount.empty()) {
         convertTo(maxActiveCount, mixPort->maxActiveCount);
     }
     // Deserialize children
     AudioGainTraits::Collection gains;
-    deserializeCollection<AudioGainTraits>(doc, child, gains, NULL);
+    status = deserializeCollection<AudioGainTraits>(doc, child, &gains, NULL);
+    if (status != NO_ERROR) {
+        return status;
+    }
     mixPort->setGains(gains);
 
     return NO_ERROR;
 }
 
-const char *const DevicePortTraits::tag = "devicePort";
-const char *const DevicePortTraits::collectionTag = "devicePorts";
-
-const char DevicePortTraits::Attributes::tagName[] = "tagName";
-const char DevicePortTraits::Attributes::type[] = "type";
-const char DevicePortTraits::Attributes::role[] = "role";
-const char DevicePortTraits::Attributes::address[] = "address";
-const char DevicePortTraits::Attributes::roleSource[] = "source";
-
-status_t DevicePortTraits::deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &deviceDesc,
+status_t DevicePortTraits::deserialize(xmlDoc *doc, const xmlNode *root, PtrElement *element,
                                        PtrSerializingCtx /*serializingContext*/)
 {
-    string name = getXmlAttribute(root, Attributes::tagName);
+    std::string name = getXmlAttribute(root, Attributes::tagName);
     if (name.empty()) {
-        ALOGE("%s: No %s found", __FUNCTION__, Attributes::tagName);
+        ALOGE("%s: No %s found", __func__, Attributes::tagName);
         return BAD_VALUE;
     }
-    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::tagName, name.c_str());
-    string typeName = getXmlAttribute(root, Attributes::type);
+    ALOGV("%s: %s %s=%s", __func__, tag, Attributes::tagName, name.c_str());
+    std::string typeName = getXmlAttribute(root, Attributes::type);
     if (typeName.empty()) {
-        ALOGE("%s: no type for %s", __FUNCTION__, name.c_str());
+        ALOGE("%s: no type for %s", __func__, name.c_str());
         return BAD_VALUE;
     }
-    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::type, typeName.c_str());
-    string role = getXmlAttribute(root, Attributes::role);
+    ALOGV("%s: %s %s=%s", __func__, tag, Attributes::type, typeName.c_str());
+    std::string role = getXmlAttribute(root, Attributes::role);
     if (role.empty()) {
-        ALOGE("%s: No %s found", __FUNCTION__, Attributes::role);
+        ALOGE("%s: No %s found", __func__, Attributes::role);
         return BAD_VALUE;
     }
-    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::role, role.c_str());
+    ALOGV("%s: %s %s=%s", __func__, tag, Attributes::role, role.c_str());
     audio_port_role_t portRole = (role == Attributes::roleSource) ?
                 AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
 
@@ -309,174 +481,173 @@
     if (!deviceFromString(typeName, type) ||
             (!audio_is_input_device(type) && portRole == AUDIO_PORT_ROLE_SOURCE) ||
             (!audio_is_output_devices(type) && portRole == AUDIO_PORT_ROLE_SINK)) {
-        ALOGW("%s: bad type %08x", __FUNCTION__, type);
+        ALOGW("%s: bad type %08x", __func__, type);
         return BAD_VALUE;
     }
-    deviceDesc = new Element(type, String8(name.c_str()));
+    PtrElement &deviceDesc = *element = new Element(type, String8(name.c_str()));
 
-    string address = getXmlAttribute(root, Attributes::address);
+    std::string address = getXmlAttribute(root, Attributes::address);
     if (!address.empty()) {
-        ALOGV("%s: address=%s for %s", __FUNCTION__, address.c_str(), name.c_str());
+        ALOGV("%s: address=%s for %s", __func__, address.c_str(), name.c_str());
         deviceDesc->mAddress = String8(address.c_str());
     }
 
     AudioProfileTraits::Collection profiles;
-    deserializeCollection<AudioProfileTraits>(doc, root, profiles, NULL);
+    status_t status = deserializeCollection<AudioProfileTraits>(doc, root, &profiles, NULL);
+    if (status != NO_ERROR) {
+        return status;
+    }
     if (profiles.isEmpty()) {
         profiles.add(AudioProfile::createFullDynamic());
     }
     deviceDesc->setAudioProfiles(profiles);
 
     // Deserialize AudioGain children
-    deserializeCollection<AudioGainTraits>(doc, root, deviceDesc->mGains, NULL);
-    ALOGV("%s: adding device tag %s type %08x address %s", __FUNCTION__,
+    status = deserializeCollection<AudioGainTraits>(doc, root, &deviceDesc->mGains, NULL);
+    if (status != NO_ERROR) {
+        return status;
+    }
+    ALOGV("%s: adding device tag %s type %08x address %s", __func__,
           deviceDesc->getName().string(), type, deviceDesc->mAddress.string());
     return NO_ERROR;
 }
 
-const char *const RouteTraits::tag = "route";
-const char *const RouteTraits::collectionTag = "routes";
-
-const char RouteTraits::Attributes::type[] = "type";
-const char RouteTraits::Attributes::typeMix[] = "mix";
-const char RouteTraits::Attributes::sink[] = "sink";
-const char RouteTraits::Attributes::sources[] = "sources";
-
-
-status_t RouteTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *root, PtrElement &element,
+status_t RouteTraits::deserialize(xmlDoc */*doc*/, const xmlNode *root, PtrElement *element,
                                   PtrSerializingCtx ctx)
 {
-    string type = getXmlAttribute(root, Attributes::type);
+    std::string type = getXmlAttribute(root, Attributes::type);
     if (type.empty()) {
-        ALOGE("%s: No %s found", __FUNCTION__, Attributes::type);
+        ALOGE("%s: No %s found", __func__, Attributes::type);
         return BAD_VALUE;
     }
     audio_route_type_t routeType = (type == Attributes::typeMix) ?
                 AUDIO_ROUTE_MIX : AUDIO_ROUTE_MUX;
 
-    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::type, type.c_str());
-    element = new Element(routeType);
+    ALOGV("%s: %s %s=%s", __func__, tag, Attributes::type, type.c_str());
+    PtrElement &route = *element = new Element(routeType);
 
-    string sinkAttr = getXmlAttribute(root, Attributes::sink);
+    std::string sinkAttr = getXmlAttribute(root, Attributes::sink);
     if (sinkAttr.empty()) {
-        ALOGE("%s: No %s found", __FUNCTION__, Attributes::sink);
+        ALOGE("%s: No %s found", __func__, Attributes::sink);
         return BAD_VALUE;
     }
     // Convert Sink name to port pointer
     sp<AudioPort> sink = ctx->findPortByTagName(String8(sinkAttr.c_str()));
     if (sink == NULL) {
-        ALOGE("%s: no sink found with name=%s", __FUNCTION__, sinkAttr.c_str());
+        ALOGE("%s: no sink found with name=%s", __func__, sinkAttr.c_str());
         return BAD_VALUE;
     }
-    element->setSink(sink);
+    route->setSink(sink);
 
-    string sourcesAttr = getXmlAttribute(root, Attributes::sources);
+    std::string sourcesAttr = getXmlAttribute(root, Attributes::sources);
     if (sourcesAttr.empty()) {
-        ALOGE("%s: No %s found", __FUNCTION__, Attributes::sources);
+        ALOGE("%s: No %s found", __func__, Attributes::sources);
         return BAD_VALUE;
     }
     // Tokenize and Convert Sources name to port pointer
     AudioPortVector sources;
-    char *sourcesLiteral = strndup(sourcesAttr.c_str(), strlen(sourcesAttr.c_str()));
-    char *devTag = strtok(sourcesLiteral, ",");
+    std::unique_ptr<char[]> sourcesLiteral{strndup(
+                sourcesAttr.c_str(), strlen(sourcesAttr.c_str()))};
+    char *devTag = strtok(sourcesLiteral.get(), ",");
     while (devTag != NULL) {
         if (strlen(devTag) != 0) {
             sp<AudioPort> source = ctx->findPortByTagName(String8(devTag));
             if (source == NULL) {
-                ALOGE("%s: no source found with name=%s", __FUNCTION__, devTag);
-                free(sourcesLiteral);
+                ALOGE("%s: no source found with name=%s", __func__, devTag);
                 return BAD_VALUE;
             }
             sources.add(source);
         }
         devTag = strtok(NULL, ",");
     }
-    free(sourcesLiteral);
 
-    sink->addRoute(element);
+    sink->addRoute(route);
     for (size_t i = 0; i < sources.size(); i++) {
         sp<AudioPort> source = sources.itemAt(i);
-        source->addRoute(element);
+        source->addRoute(route);
     }
-    element->setSources(sources);
+    route->setSources(sources);
     return NO_ERROR;
 }
 
-const char *const ModuleTraits::childAttachedDevicesTag = "attachedDevices";
-const char *const ModuleTraits::childAttachedDeviceTag = "item";
-const char *const ModuleTraits::childDefaultOutputDeviceTag = "defaultOutputDevice";
-
-const char *const ModuleTraits::tag = "module";
-const char *const ModuleTraits::collectionTag = "modules";
-
-const char ModuleTraits::Attributes::name[] = "name";
-const char ModuleTraits::Attributes::version[] = "halVersion";
-
-status_t ModuleTraits::deserialize(xmlDocPtr doc, const xmlNode *root, PtrElement &module,
+status_t ModuleTraits::deserialize(xmlDocPtr doc, const xmlNode *root, PtrElement *element,
                                    PtrSerializingCtx ctx)
 {
-    string name = getXmlAttribute(root, Attributes::name);
+    std::string name = getXmlAttribute(root, Attributes::name);
     if (name.empty()) {
-        ALOGE("%s: No %s found", __FUNCTION__, Attributes::name);
+        ALOGE("%s: No %s found", __func__, Attributes::name);
         return BAD_VALUE;
     }
     uint32_t versionMajor = 0, versionMinor = 0;
-    string versionLiteral = getXmlAttribute(root, Attributes::version);
+    std::string versionLiteral = getXmlAttribute(root, Attributes::version);
     if (!versionLiteral.empty()) {
         sscanf(versionLiteral.c_str(), "%u.%u", &versionMajor, &versionMinor);
-        ALOGV("%s: mHalVersion = major %u minor %u",  __FUNCTION__,
+        ALOGV("%s: mHalVersion = major %u minor %u",  __func__,
               versionMajor, versionMajor);
     }
 
-    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::name, name.c_str());
+    ALOGV("%s: %s %s=%s", __func__, tag, Attributes::name, name.c_str());
 
-    module = new Element(name.c_str(), versionMajor, versionMinor);
+    PtrElement &module = *element = new Element(name.c_str(), versionMajor, versionMinor);
 
     // Deserialize childrens: Audio Mix Port, Audio Device Ports (Source/Sink), Audio Routes
     MixPortTraits::Collection mixPorts;
-    deserializeCollection<MixPortTraits>(doc, root, mixPorts, NULL);
+    status_t status = deserializeCollection<MixPortTraits>(doc, root, &mixPorts, NULL);
+    if (status != NO_ERROR) {
+        return status;
+    }
     module->setProfiles(mixPorts);
 
     DevicePortTraits::Collection devicePorts;
-    deserializeCollection<DevicePortTraits>(doc, root, devicePorts, NULL);
+    status = deserializeCollection<DevicePortTraits>(doc, root, &devicePorts, NULL);
+    if (status != NO_ERROR) {
+        return status;
+    }
     module->setDeclaredDevices(devicePorts);
 
     RouteTraits::Collection routes;
-    deserializeCollection<RouteTraits>(doc, root, routes, module.get());
+    status = deserializeCollection<RouteTraits>(doc, root, &routes, module.get());
+    if (status != NO_ERROR) {
+        return status;
+    }
     module->setRoutes(routes);
 
     const xmlNode *children = root->xmlChildrenNode;
     while (children != NULL) {
-        if (!xmlStrcmp(children->name, (const xmlChar *)childAttachedDevicesTag)) {
-            ALOGV("%s: %s %s found", __FUNCTION__, tag, childAttachedDevicesTag);
+        if (!xmlStrcmp(children->name, reinterpret_cast<const xmlChar*>(childAttachedDevicesTag))) {
+            ALOGV("%s: %s %s found", __func__, tag, childAttachedDevicesTag);
             const xmlNode *child = children->xmlChildrenNode;
             while (child != NULL) {
-                if (!xmlStrcmp(child->name, (const xmlChar *)childAttachedDeviceTag)) {
-                    xmlChar *attachedDevice = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
-                    if (attachedDevice != NULL) {
-                        ALOGV("%s: %s %s=%s", __FUNCTION__, tag, childAttachedDeviceTag,
-                              (const char*)attachedDevice);
-                        sp<DeviceDescriptor> device =
-                                module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)attachedDevice));
+                if (!xmlStrcmp(child->name,
+                                reinterpret_cast<const xmlChar*>(childAttachedDeviceTag))) {
+                    auto attachedDevice = make_xmlUnique(xmlNodeListGetString(
+                                    doc, child->xmlChildrenNode, 1));
+                    if (attachedDevice != nullptr) {
+                        ALOGV("%s: %s %s=%s", __func__, tag, childAttachedDeviceTag,
+                                reinterpret_cast<const char*>(attachedDevice.get()));
+                        sp<DeviceDescriptor> device = module->getDeclaredDevices().
+                                getDeviceFromTagName(String8(reinterpret_cast<const char*>(
+                                                        attachedDevice.get())));
                         ctx->addAvailableDevice(device);
-                        xmlFree(attachedDevice);
                     }
                 }
                 child = child->next;
             }
         }
-        if (!xmlStrcmp(children->name, (const xmlChar *)childDefaultOutputDeviceTag)) {
-            xmlChar *defaultOutputDevice = xmlNodeListGetString(doc, children->xmlChildrenNode, 1);;
-            if (defaultOutputDevice != NULL) {
-                ALOGV("%s: %s %s=%s", __FUNCTION__, tag, childDefaultOutputDeviceTag,
-                      (const char*)defaultOutputDevice);
-                sp<DeviceDescriptor> device =
-                        module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)defaultOutputDevice));
+        if (!xmlStrcmp(children->name,
+                        reinterpret_cast<const xmlChar*>(childDefaultOutputDeviceTag))) {
+            auto defaultOutputDevice = make_xmlUnique(xmlNodeListGetString(
+                            doc, children->xmlChildrenNode, 1));
+            if (defaultOutputDevice != nullptr) {
+                ALOGV("%s: %s %s=%s", __func__, tag, childDefaultOutputDeviceTag,
+                        reinterpret_cast<const char*>(defaultOutputDevice.get()));
+                sp<DeviceDescriptor> device = module->getDeclaredDevices().getDeviceFromTagName(
+                        String8(reinterpret_cast<const char*>(defaultOutputDevice.get())));
                 if (device != 0 && ctx->getDefaultOutputDevice() == 0) {
                     ctx->setDefaultOutputDevice(device);
-                    ALOGV("%s: default is %08x", __FUNCTION__, ctx->getDefaultOutputDevice()->type());
+                    ALOGV("%s: default is %08x",
+                            __func__, ctx->getDefaultOutputDevice()->type());
                 }
-                xmlFree(defaultOutputDevice);
             }
         }
         children = children->next;
@@ -484,22 +655,17 @@
     return NO_ERROR;
 }
 
-const char *const GlobalConfigTraits::tag = "globalConfiguration";
-
-const char GlobalConfigTraits::Attributes::speakerDrcEnabled[] = "speaker_drc_enabled";
-
-
-status_t GlobalConfigTraits::deserialize(const xmlNode *cur, AudioPolicyConfig &config)
+status_t GlobalConfigTraits::deserialize(const xmlNode *cur, AudioPolicyConfig *config)
 {
     const xmlNode *root = cur->xmlChildrenNode;
     while (root != NULL) {
-        if (!xmlStrcmp(root->name, (const xmlChar *)tag)) {
-            string speakerDrcEnabled =
+        if (!xmlStrcmp(root->name, reinterpret_cast<const xmlChar*>(tag))) {
+            std::string speakerDrcEnabled =
                     getXmlAttribute(root, Attributes::speakerDrcEnabled);
             bool isSpeakerDrcEnabled;
             if (!speakerDrcEnabled.empty() &&
-                    convertTo<string, bool>(speakerDrcEnabled, isSpeakerDrcEnabled)) {
-                config.setSpeakerDrcEnabled(isSpeakerDrcEnabled);
+                    convertTo<std::string, bool>(speakerDrcEnabled, isSpeakerDrcEnabled)) {
+                config->setSpeakerDrcEnabled(isSpeakerDrcEnabled);
             }
             return NO_ERROR;
         }
@@ -508,134 +674,129 @@
     return NO_ERROR;
 }
 
-
-const char *const VolumeTraits::tag = "volume";
-const char *const VolumeTraits::collectionTag = "volumes";
-const char *const VolumeTraits::volumePointTag = "point";
-
-const char VolumeTraits::Attributes::stream[] = "stream";
-const char VolumeTraits::Attributes::deviceCategory[] = "deviceCategory";
-const char VolumeTraits::Attributes::reference[] = "ref";
-
-status_t VolumeTraits::deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
+status_t VolumeTraits::deserialize(xmlDoc *doc, const xmlNode *root, PtrElement *element,
                                    PtrSerializingCtx /*serializingContext*/)
 {
-    string streamTypeLiteral = getXmlAttribute(root, Attributes::stream);
+    std::string streamTypeLiteral = getXmlAttribute(root, Attributes::stream);
     if (streamTypeLiteral.empty()) {
-        ALOGE("%s: No %s found", __FUNCTION__, Attributes::stream);
+        ALOGE("%s: No %s found", __func__, Attributes::stream);
         return BAD_VALUE;
     }
     audio_stream_type_t streamType;
     if (!StreamTypeConverter::fromString(streamTypeLiteral, streamType)) {
-        ALOGE("%s: Invalid %s", __FUNCTION__, Attributes::stream);
+        ALOGE("%s: Invalid %s", __func__, Attributes::stream);
         return BAD_VALUE;
     }
-    string deviceCategoryLiteral = getXmlAttribute(root, Attributes::deviceCategory);
+    std::string deviceCategoryLiteral = getXmlAttribute(root, Attributes::deviceCategory);
     if (deviceCategoryLiteral.empty()) {
-        ALOGE("%s: No %s found", __FUNCTION__, Attributes::deviceCategory);
+        ALOGE("%s: No %s found", __func__, Attributes::deviceCategory);
         return BAD_VALUE;
     }
     device_category deviceCategory;
     if (!DeviceCategoryConverter::fromString(deviceCategoryLiteral, deviceCategory)) {
-        ALOGE("%s: Invalid %s=%s", __FUNCTION__, Attributes::deviceCategory,
+        ALOGE("%s: Invalid %s=%s", __func__, Attributes::deviceCategory,
               deviceCategoryLiteral.c_str());
         return BAD_VALUE;
     }
 
-    string referenceName = getXmlAttribute(root, Attributes::reference);
-    const _xmlNode *ref = NULL;
+    std::string referenceName = getXmlAttribute(root, Attributes::reference);
+    const xmlNode *ref = NULL;
     if (!referenceName.empty()) {
-        getReference<VolumeTraits>(root->parent, ref, referenceName);
+        ref = getReference<VolumeTraits>(root->parent, referenceName);
         if (ref == NULL) {
-            ALOGE("%s: No reference Ptr found for %s", __FUNCTION__, referenceName.c_str());
+            ALOGE("%s: No reference Ptr found for %s", __func__, referenceName.c_str());
             return BAD_VALUE;
         }
     }
 
-    element = new Element(deviceCategory, streamType);
+    PtrElement &volCurve = *element = new Element(deviceCategory, streamType);
 
     const xmlNode *child = referenceName.empty() ? root->xmlChildrenNode : ref->xmlChildrenNode;
     while (child != NULL) {
-        if (!xmlStrcmp(child->name, (const xmlChar *)volumePointTag)) {
-            xmlChar *pointDefinition = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);;
-            if (pointDefinition == NULL) {
+        if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>(volumePointTag))) {
+            auto pointDefinition = make_xmlUnique(xmlNodeListGetString(
+                            doc, child->xmlChildrenNode, 1));
+            if (pointDefinition == nullptr) {
                 return BAD_VALUE;
             }
-            ALOGV("%s: %s=%s", __FUNCTION__, tag, (const char*)pointDefinition);
+            ALOGV("%s: %s=%s",
+                    __func__, tag, reinterpret_cast<const char*>(pointDefinition.get()));
             Vector<int32_t> point;
-            collectionFromString<DefaultTraits<int32_t> >((const char*)pointDefinition, point, ",");
+            collectionFromString<DefaultTraits<int32_t>>(
+                    reinterpret_cast<const char*>(pointDefinition.get()), point, ",");
             if (point.size() != 2) {
-                ALOGE("%s: Invalid %s: %s", __FUNCTION__, volumePointTag,
-                      (const char*)pointDefinition);
+                ALOGE("%s: Invalid %s: %s", __func__, volumePointTag,
+                        reinterpret_cast<const char*>(pointDefinition.get()));
                 return BAD_VALUE;
             }
-            element->add(CurvePoint(point[0], point[1]));
-            xmlFree(pointDefinition);
+            volCurve->add(CurvePoint(point[0], point[1]));
         }
         child = child->next;
     }
     return NO_ERROR;
 }
 
-PolicySerializer::PolicySerializer() : mRootElementName(rootName)
+status_t PolicySerializer::deserialize(const char *configFile, AudioPolicyConfig *config)
 {
-    std::ostringstream oss;
-    oss << gMajor << "." << gMinor;
-    mVersion = oss.str();
-    ALOGV("%s: Version=%s Root=%s", __FUNCTION__, mVersion.c_str(), mRootElementName.c_str());
-}
-
-status_t PolicySerializer::deserialize(const char *configFile, AudioPolicyConfig &config)
-{
-    xmlDocPtr doc;
-    doc = xmlParseFile(configFile);
-    if (doc == NULL) {
-        ALOGE("%s: Could not parse %s document.", __FUNCTION__, configFile);
+    auto doc = make_xmlUnique(xmlParseFile(configFile));
+    if (doc == nullptr) {
+        ALOGE("%s: Could not parse %s document.", __func__, configFile);
         return BAD_VALUE;
     }
-    xmlNodePtr cur = xmlDocGetRootElement(doc);
+    xmlNodePtr cur = xmlDocGetRootElement(doc.get());
     if (cur == NULL) {
-        ALOGE("%s: Could not parse %s document: empty.", __FUNCTION__, configFile);
-        xmlFreeDoc(doc);
+        ALOGE("%s: Could not parse %s document: empty.", __func__, configFile);
         return BAD_VALUE;
     }
-    if (xmlXIncludeProcess(doc) < 0) {
-         ALOGE("%s: libxml failed to resolve XIncludes on %s document.", __FUNCTION__, configFile);
+    if (xmlXIncludeProcess(doc.get()) < 0) {
+        ALOGE("%s: libxml failed to resolve XIncludes on %s document.", __func__, configFile);
     }
 
-    if (xmlStrcmp(cur->name, (const xmlChar *) mRootElementName.c_str()))  {
-        ALOGE("%s: No %s root element found in xml data %s.", __FUNCTION__, mRootElementName.c_str(),
-              (const char *)cur->name);
-        xmlFreeDoc(doc);
+    if (xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(rootName)))  {
+        ALOGE("%s: No %s root element found in xml data %s.", __func__, rootName,
+                reinterpret_cast<const char*>(cur->name));
         return BAD_VALUE;
     }
 
-    string version = getXmlAttribute(cur, versionAttribute);
+    std::string version = getXmlAttribute(cur, versionAttribute);
     if (version.empty()) {
-        ALOGE("%s: No version found in root node %s", __FUNCTION__, mRootElementName.c_str());
+        ALOGE("%s: No version found in root node %s", __func__, rootName);
         return BAD_VALUE;
     }
     if (version != mVersion) {
-        ALOGE("%s: Version does not match; expect %s got %s", __FUNCTION__, mVersion.c_str(),
+        ALOGE("%s: Version does not match; expect %s got %s", __func__, mVersion.c_str(),
               version.c_str());
         return BAD_VALUE;
     }
     // Lets deserialize children
     // Modules
     ModuleTraits::Collection modules;
-    deserializeCollection<ModuleTraits>(doc, cur, modules, &config);
-    config.setHwModules(modules);
+    status_t status = deserializeCollection<ModuleTraits>(doc.get(), cur, &modules, config);
+    if (status != NO_ERROR) {
+        return status;
+    }
+    config->setHwModules(modules);
 
     // deserialize volume section
     VolumeTraits::Collection volumes;
-    deserializeCollection<VolumeTraits>(doc, cur, volumes, &config);
-    config.setVolumes(volumes);
+    status = deserializeCollection<VolumeTraits>(doc.get(), cur, &volumes, config);
+    if (status != NO_ERROR) {
+        return status;
+    }
+    config->setVolumes(volumes);
 
     // Global Configuration
     GlobalConfigTraits::deserialize(cur, config);
 
-    xmlFreeDoc(doc);
     return android::OK;
 }
 
+}  // namespace
+
+status_t deserializeAudioPolicyFile(const char *fileName, AudioPolicyConfig *config)
+{
+    PolicySerializer serializer;
+    return serializer.deserialize(fileName, config);
+}
+
 } // namespace android
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index dd2158b..600f968 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -3921,10 +3921,9 @@
 
     for (const char* fileName : fileNames) {
         for (int i = 0; i < kConfigLocationListSize; i++) {
-            PolicySerializer serializer;
             snprintf(audioPolicyXmlConfigFile, sizeof(audioPolicyXmlConfigFile),
                      "%s/%s", kConfigLocationList[i], fileName);
-            ret = serializer.deserialize(audioPolicyXmlConfigFile, config);
+            ret = deserializeAudioPolicyFile(audioPolicyXmlConfigFile, &config);
             if (ret == NO_ERROR) {
                 config.setSource(audioPolicyXmlConfigFile);
                 return ret;
diff --git a/services/mediaanalytics/MediaAnalyticsService.cpp b/services/mediaanalytics/MediaAnalyticsService.cpp
index 45da56a..ae832ba 100644
--- a/services/mediaanalytics/MediaAnalyticsService.cpp
+++ b/services/mediaanalytics/MediaAnalyticsService.cpp
@@ -26,6 +26,7 @@
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <dirent.h>
+#include <pthread.h>
 #include <unistd.h>
 
 #include <string.h>
@@ -80,11 +81,18 @@
     using namespace android::content::pm;
 
 // individual records kept in memory: age or count
-// age: <= 36 hours (1.5 days)
+// age: <= 28 hours (1 1/6 days)
 // count: hard limit of # records
 // (0 for either of these disables that threshold)
-static const nsecs_t kMaxRecordAgeNs =  36 * 3600 * (1000*1000*1000ll);
-static const int kMaxRecords    = 0;
+//
+static constexpr nsecs_t kMaxRecordAgeNs =  28 * 3600 * (1000*1000*1000ll);
+static constexpr int kMaxRecords    = 0;
+
+// max we expire in a single call, to constrain how long we hold the
+// mutex, which also constrains how long a client might wait.
+static constexpr int kMaxExpiredAtOnce = 50;
+
+// TODO: need to look at tuning kMaxRecords and friends for low-memory devices
 
 static const char *kServiceName = "media.metrics";
 
@@ -96,6 +104,7 @@
 MediaAnalyticsService::MediaAnalyticsService()
         : mMaxRecords(kMaxRecords),
           mMaxRecordAgeNs(kMaxRecordAgeNs),
+          mMaxRecordsExpiredAtOnce(kMaxExpiredAtOnce),
           mDumpProto(MediaAnalyticsItem::PROTO_V1),
           mDumpProtoDefault(MediaAnalyticsItem::PROTO_V1) {
 
@@ -432,23 +441,29 @@
 //
 // Our Cheap in-core, non-persistent records management.
 
-// insert appropriately into queue
-void MediaAnalyticsService::saveItem(MediaAnalyticsItem * item)
+
+// we hold mLock when we get here
+// if item != NULL, it's the item we just inserted
+// true == more items eligible to be recovered
+bool MediaAnalyticsService::expirations_l(MediaAnalyticsItem *item)
 {
-
-    Mutex::Autolock _l(mLock);
-    // mutex between insertion and dumping the contents
-
-    // we want to dump 'in FIFO order', so insert at the end
-    mItems.push_back(item);
+    bool more = false;
+    int handled = 0;
 
     // keep removing old records the front until we're in-bounds (count)
+    // since we invoke this with each insertion, it should be 0/1 iterations.
     if (mMaxRecords > 0) {
         while (mItems.size() > (size_t) mMaxRecords) {
             MediaAnalyticsItem * oitem = *(mItems.begin());
             if (oitem == item) {
                 break;
             }
+            if (handled >= mMaxRecordsExpiredAtOnce) {
+                // unlikely in this loop
+                more = true;
+                break;
+            }
+            handled++;
             mItems.erase(mItems.begin());
             delete oitem;
             mItemsDiscarded++;
@@ -456,8 +471,8 @@
         }
     }
 
-    // keep removing old records the front until we're in-bounds (count)
-    // NB: expired entries aren't removed until the next insertion, which could be a while
+    // keep removing old records the front until we're in-bounds (age)
+    // limited to mMaxRecordsExpiredAtOnce items per invocation.
     if (mMaxRecordAgeNs > 0) {
         nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
         while (mItems.size() > 0) {
@@ -471,12 +486,65 @@
                 // this (and the rest) are recent enough to keep
                 break;
             }
+            if (handled >= mMaxRecordsExpiredAtOnce) {
+                // this represents "one too many"; tell caller there are
+                // more to be reclaimed.
+                more = true;
+                break;
+            }
+            handled++;
             mItems.erase(mItems.begin());
             delete oitem;
             mItemsDiscarded++;
             mItemsDiscardedExpire++;
         }
     }
+
+    // we only indicate whether there's more to clean;
+    // caller chooses whether to schedule further cleanup.
+    return more;
+}
+
+// process expirations in bite sized chunks, allowing new insertions through
+// runs in a pthread specifically started for this (which then exits)
+bool MediaAnalyticsService::processExpirations()
+{
+    bool more;
+    do {
+        sleep(1);
+        {
+            Mutex::Autolock _l(mLock);
+            more = expirations_l(NULL);
+            if (!more) {
+                break;
+            }
+        }
+    } while (more);
+    return true;        // value is for std::future thread synchronization
+}
+
+// insert appropriately into queue
+void MediaAnalyticsService::saveItem(MediaAnalyticsItem * item)
+{
+
+    Mutex::Autolock _l(mLock);
+    // mutex between insertion and dumping the contents
+
+    // we want to dump 'in FIFO order', so insert at the end
+    mItems.push_back(item);
+
+    // clean old stuff from the queue
+    bool more = expirations_l(item);
+
+    // consider scheduling some asynchronous cleaning, if not running
+    if (more) {
+        if (!mExpireFuture.valid()
+            || mExpireFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
+
+            mExpireFuture = std::async(std::launch::async, [this]()
+                                       {return this->processExpirations();});
+        }
+    }
 }
 
 static std::string allowedKeys[] =
diff --git a/services/mediaanalytics/MediaAnalyticsService.h b/services/mediaanalytics/MediaAnalyticsService.h
index b3c902a..632c692 100644
--- a/services/mediaanalytics/MediaAnalyticsService.h
+++ b/services/mediaanalytics/MediaAnalyticsService.h
@@ -26,6 +26,8 @@
 #include <utils/String8.h>
 #include <utils/List.h>
 
+#include <future>
+
 #include <media/IMediaAnalyticsService.h>
 
 namespace android {
@@ -44,6 +46,8 @@
                             MediaAnalyticsService();
     virtual                 ~MediaAnalyticsService();
 
+    bool processExpirations();
+
  private:
     MediaAnalyticsItem::SessionID_t generateUniqueSessionID();
 
@@ -65,6 +69,8 @@
     int32_t mMaxRecords;
     // by time (none older than this long agan
     nsecs_t mMaxRecordAgeNs;
+    // max to expire per expirations_l() invocation
+    int32_t mMaxRecordsExpiredAtOnce;
     //
     // # of sets of summaries
     int32_t mMaxRecordSets;
@@ -79,6 +85,9 @@
     List<MediaAnalyticsItem *> mItems;
     void saveItem(MediaAnalyticsItem *);
 
+    bool expirations_l(MediaAnalyticsItem *);
+    std::future<bool> mExpireFuture;
+
     // support for generating output
     int mDumpProto;
     int mDumpProtoDefault;