Merge changes from topic 'codec-surface' into mnc-dev

* changes:
  stagefright: enable experiments
  stagefright: allow connecting to surfaces that attach buffers
diff --git a/include/media/MediaResourcePolicy.h b/include/media/MediaResourcePolicy.h
index 1e1c341..9bc2eec 100644
--- a/include/media/MediaResourcePolicy.h
+++ b/include/media/MediaResourcePolicy.h
@@ -29,7 +29,7 @@
 class MediaResourcePolicy {
 public:
     MediaResourcePolicy();
-    MediaResourcePolicy(String8 type, uint64_t value);
+    MediaResourcePolicy(String8 type, String8 value);
 
     void readFromParcel(const Parcel &parcel);
     void writeToParcel(Parcel *parcel) const;
@@ -37,7 +37,7 @@
     String8 toString() const;
 
     String8 mType;
-    uint64_t mValue;
+    String8 mValue;
 };
 
 }; // namespace android
diff --git a/include/media/stagefright/MediaCodecList.h b/include/media/stagefright/MediaCodecList.h
index 9d1d675..ce34338 100644
--- a/include/media/stagefright/MediaCodecList.h
+++ b/include/media/stagefright/MediaCodecList.h
@@ -54,7 +54,7 @@
     static sp<IMediaCodecList> getLocalInstance();
 
     // only to be used in getLocalInstance
-    void updateDetailsForMultipleCodecs(const KeyedVector<AString, CodecSettings>& updates);
+    void parseTopLevelXMLFile(const char *path, bool ignore_errors = false);
 
 private:
     class BinderDeathObserver : public IBinder::DeathRecipient {
@@ -97,7 +97,6 @@
 
     status_t initCheck() const;
     void parseXMLFile(const char *path);
-    void parseTopLevelXMLFile(const char *path, bool ignore_errors = false);
 
     static void StartElementHandlerWrapper(
             void *me, const char *name, const char **attrs);
diff --git a/media/libmedia/MediaResourcePolicy.cpp b/media/libmedia/MediaResourcePolicy.cpp
index 139a38c..5210825 100644
--- a/media/libmedia/MediaResourcePolicy.cpp
+++ b/media/libmedia/MediaResourcePolicy.cpp
@@ -24,25 +24,25 @@
 const char kPolicySupportsMultipleSecureCodecs[] = "supports-multiple-secure-codecs";
 const char kPolicySupportsSecureWithNonSecureCodec[] = "supports-secure-with-non-secure-codec";
 
-MediaResourcePolicy::MediaResourcePolicy() : mValue(0) {}
+MediaResourcePolicy::MediaResourcePolicy() {}
 
-MediaResourcePolicy::MediaResourcePolicy(String8 type, uint64_t value)
+MediaResourcePolicy::MediaResourcePolicy(String8 type, String8 value)
         : mType(type),
           mValue(value) {}
 
 void MediaResourcePolicy::readFromParcel(const Parcel &parcel) {
     mType = parcel.readString8();
-    mValue = parcel.readUint64();
+    mValue = parcel.readString8();
 }
 
 void MediaResourcePolicy::writeToParcel(Parcel *parcel) const {
     parcel->writeString8(mType);
-    parcel->writeUint64(mValue);
+    parcel->writeString8(mValue);
 }
 
 String8 MediaResourcePolicy::toString() const {
     String8 str;
-    str.appendFormat("%s:%llu", mType.string(), (unsigned long long)mValue);
+    str.appendFormat("%s:%s", mType.string(), mValue.string());
     return str;
 }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index a118dec..1fb4365 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -189,7 +189,8 @@
       mVideoFpsHint(-1.f),
       mStarted(false),
       mPaused(false),
-      mPausedByClient(false) {
+      mPausedByClient(false),
+      mPausedForBuffering(false) {
     clearFlushComplete();
 }
 
@@ -683,7 +684,10 @@
         {
             ALOGV("kWhatStart");
             if (mStarted) {
-                onResume();
+                // do not resume yet if the source is still buffering
+                if (!mPausedForBuffering) {
+                    onResume();
+                }
             } else {
                 onStart();
             }
@@ -2007,9 +2011,10 @@
         case Source::kWhatPauseOnBufferingStart:
         {
             // ignore if not playing
-            if (mStarted && !mPausedByClient) {
+            if (mStarted) {
                 ALOGI("buffer low, pausing...");
 
+                mPausedForBuffering = true;
                 onPause();
             }
             // fall-thru
@@ -2024,10 +2029,15 @@
         case Source::kWhatResumeOnBufferingEnd:
         {
             // ignore if not playing
-            if (mStarted && !mPausedByClient) {
+            if (mStarted) {
                 ALOGI("buffer ready, resuming...");
 
-                onResume();
+                mPausedForBuffering = false;
+
+                // do not resume yet if client didn't unpause
+                if (!mPausedByClient) {
+                    onResume();
+                }
             }
             // fall-thru
         }
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 6b7d71e..df9debc 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -203,6 +203,9 @@
     // still become true, when we pause internally due to buffering.
     bool mPausedByClient;
 
+    // Pause state as requested by source (internally) due to buffering
+    bool mPausedForBuffering;
+
     inline const sp<DecoderBase> &getDecoder(bool audio) {
         return audio ? mAudioDecoder : mVideoDecoder;
     }
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 6573afc..5c0afa9 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -1981,6 +1981,10 @@
                 size = 0;
             }
 
+            if (SIZE_MAX - chunk_size <= size) {
+                return ERROR_MALFORMED;
+            }
+
             uint8_t *buffer = new (std::nothrow) uint8_t[size + chunk_size];
             if (buffer == NULL) {
                 return ERROR_MALFORMED;
@@ -2014,14 +2018,22 @@
             *offset += chunk_size;
 
             if (mFileMetaData != NULL) {
-                ALOGV("chunk_data_size = %lld and data_offset = %lld",
-                        (long long)chunk_data_size, (long long)data_offset);
+                ALOGV("chunk_data_size = %" PRId64 " and data_offset = %" PRId64,
+                      chunk_data_size, data_offset);
+
+                if (chunk_data_size < 0 || static_cast<uint64_t>(chunk_data_size) >= SIZE_MAX - 1) {
+                    return ERROR_MALFORMED;
+                }
                 sp<ABuffer> buffer = new ABuffer(chunk_data_size + 1);
                 if (mDataSource->readAt(
                     data_offset, buffer->data(), chunk_data_size) != (ssize_t)chunk_data_size) {
                     return ERROR_IO;
                 }
                 const int kSkipBytesOfDataBox = 16;
+                if (chunk_data_size <= kSkipBytesOfDataBox) {
+                    return ERROR_MALFORMED;
+                }
+
                 mFileMetaData->setData(
                     kKeyAlbumArt, MetaData::TYPE_NONE,
                     buffer->data() + kSkipBytesOfDataBox, chunk_data_size - kSkipBytesOfDataBox);
@@ -2605,11 +2617,11 @@
 }
 
 status_t MPEG4Extractor::parse3GPPMetaData(off64_t offset, size_t size, int depth) {
-    if (size < 4) {
+    if (size < 4 || size == SIZE_MAX) {
         return ERROR_MALFORMED;
     }
 
-    uint8_t *buffer = new (std::nothrow) uint8_t[size];
+    uint8_t *buffer = new (std::nothrow) uint8_t[size + 1];
     if (buffer == NULL) {
         return ERROR_MALFORMED;
     }
@@ -2678,6 +2690,10 @@
         int len16 = 0; // Number of UTF-16 characters
 
         // smallest possible valid UTF-16 string w BOM: 0xfe 0xff 0x00 0x00
+        if (size < 6) {
+            return ERROR_MALFORMED;
+        }
+
         if (size - 6 >= 4) {
             len16 = ((size - 6) / 2) - 1; // don't include 0x0000 terminator
             framedata = (char16_t *)(buffer + 6);
@@ -2701,6 +2717,7 @@
         }
 
         if (isUTF8) {
+            buffer[size] = 0;
             mFileMetaData->setCString(metadataKey, (const char *)buffer + 6);
         } else {
             // Convert from UTF-16 string to UTF-8 string.
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index f12a913..d2352bc 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -24,7 +24,9 @@
 
 #include <media/IMediaCodecList.h>
 #include <media/IMediaPlayerService.h>
+#include <media/IResourceManagerService.h>
 #include <media/MediaCodecInfo.h>
+#include <media/MediaResourcePolicy.h>
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -44,8 +46,6 @@
 
 static MediaCodecList *gCodecList = NULL;
 
-static const char *kProfilingResults = "/data/misc/media/media_codecs_profiling_results.xml";
-
 static bool parseBoolean(const char *s) {
     if (!strcasecmp(s, "true") || !strcasecmp(s, "yes") || !strcasecmp(s, "y")) {
         return true;
@@ -61,7 +61,6 @@
 // static
 sp<IMediaCodecList> MediaCodecList::getLocalInstance() {
     bool profilingNeeded = false;
-    KeyedVector<AString, CodecSettings> updates;
     Vector<sp<MediaCodecInfo>> infos;
 
     {
@@ -89,13 +88,13 @@
     }
 
     if (profilingNeeded) {
-        profileCodecs(infos, &updates);
+        profileCodecs(infos);
     }
 
     {
         Mutex::Autolock autoLock(sInitMutex);
-        if (updates.size() > 0) {
-            gCodecList->updateDetailsForMultipleCodecs(updates);
+        if (profilingNeeded) {
+            gCodecList->parseTopLevelXMLFile(kProfilingResults, true /* ignore_errors */);
         }
 
         return sCodecList;
@@ -145,19 +144,6 @@
     parseTopLevelXMLFile(kProfilingResults, true/* ignore_errors */);
 }
 
-void MediaCodecList::updateDetailsForMultipleCodecs(
-        const KeyedVector<AString, CodecSettings>& updates) {
-    if (updates.size() == 0) {
-        return;
-    }
-
-    exportResultsToXML(kProfilingResults, updates);
-
-    for (size_t i = 0; i < updates.size(); ++i) {
-        applyCodecSettings(updates.keyAt(i), updates.valueAt(i), &mCodecInfos);
-    }
-}
-
 void MediaCodecList::parseTopLevelXMLFile(const char *codecs_xml, bool ignore_errors) {
     // get href_base
     char *href_base_end = strrchr(codecs_xml, '/');
@@ -187,6 +173,25 @@
         return;
     }
 
+    Vector<MediaResourcePolicy> policies;
+    AString value;
+    if (mGlobalSettings->findString(kPolicySupportsMultipleSecureCodecs, &value)) {
+        policies.push_back(
+                MediaResourcePolicy(
+                        String8(kPolicySupportsMultipleSecureCodecs),
+                        String8(value.c_str())));
+    }
+    if (policies.size() > 0) {
+        sp<IServiceManager> sm = defaultServiceManager();
+        sp<IBinder> binder = sm->getService(String16("media.resource_manager"));
+        sp<IResourceManagerService> service = interface_cast<IResourceManagerService>(binder);
+        if (service == NULL) {
+            ALOGE("MediaCodecList: failed to get ResourceManagerService");
+        } else {
+            service->config(policies);
+        }
+    }
+
     for (size_t i = mCodecInfos.size(); i-- > 0;) {
         const MediaCodecInfo &info = *mCodecInfos.itemAt(i).get();
         if (info.mCaps.size() == 0) {
diff --git a/media/libstagefright/MediaCodecListOverrides.cpp b/media/libstagefright/MediaCodecListOverrides.cpp
index 265b1ea..0d95676 100644
--- a/media/libstagefright/MediaCodecListOverrides.cpp
+++ b/media/libstagefright/MediaCodecListOverrides.cpp
@@ -24,12 +24,14 @@
 #include <media/ICrypto.h>
 #include <media/IMediaCodecList.h>
 #include <media/MediaCodecInfo.h>
-
+#include <media/MediaResourcePolicy.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/MediaCodec.h>
 
 namespace android {
 
+const char *kProfilingResults = "/data/misc/media/media_codecs_profiling_results.xml";
+
 // a limit to avoid allocating unreasonable number of codec instances in the measurement.
 // this should be in sync with the MAX_SUPPORTED_INSTANCES defined in MediaCodecInfo.java.
 static const int kMaxInstances = 32;
@@ -171,20 +173,6 @@
     return codecs.size();
 }
 
-static void printLongString(const char *buf, size_t size) {
-    AString print;
-    const char *start = buf;
-    size_t len;
-    size_t totalLen = size;
-    while (totalLen > 0) {
-        len = (totalLen > 500) ? 500 : totalLen;
-        print.setTo(start, len);
-        ALOGV("%s", print.c_str());
-        totalLen -= len;
-        start += len;
-    }
-}
-
 bool splitString(const AString &s, const AString &delimiter, AString *s1, AString *s2) {
     ssize_t pos = s.find(delimiter.c_str());
     if (pos < 0) {
@@ -207,11 +195,22 @@
     return true;
 }
 
+void profileCodecs(const Vector<sp<MediaCodecInfo>> &infos) {
+    CodecSettings global_results;
+    KeyedVector<AString, CodecSettings> encoder_results;
+    KeyedVector<AString, CodecSettings> decoder_results;
+    profileCodecs(infos, &global_results, &encoder_results, &decoder_results);
+    exportResultsToXML(kProfilingResults, global_results, encoder_results, decoder_results);
+}
+
 void profileCodecs(
         const Vector<sp<MediaCodecInfo>> &infos,
-        KeyedVector<AString, CodecSettings> *results,
+        CodecSettings *global_results,
+        KeyedVector<AString, CodecSettings> *encoder_results,
+        KeyedVector<AString, CodecSettings> *decoder_results,
         bool forceToMeasure) {
     KeyedVector<AString, sp<MediaCodecInfo::Capabilities>> codecsNeedMeasure;
+    AString supportMultipleSecureCodecs = "true";
     for (size_t i = 0; i < infos.size(); ++i) {
         const sp<MediaCodecInfo> info = infos[i];
         AString name = info->getCodecName();
@@ -240,157 +239,93 @@
                 AString key = name;
                 key.append(" ");
                 key.append(mimes[i]);
-                key.append(" ");
-                key.append(info->isEncoder() ? "encoder" : "decoder");
-                results->add(key, settings);
+
+                if (info->isEncoder()) {
+                    encoder_results->add(key, settings);
+                } else {
+                    decoder_results->add(key, settings);
+                }
+
+                if (name.endsWith(".secure")) {
+                    if (max <= 1) {
+                        supportMultipleSecureCodecs = "false";
+                    }
+                }
             }
         }
     }
+    global_results->add(kPolicySupportsMultipleSecureCodecs, supportMultipleSecureCodecs);
 }
 
-void applyCodecSettings(
-        const AString& codecInfo,
-        const CodecSettings &settings,
-        Vector<sp<MediaCodecInfo>> *infos) {
-    AString name;
-    AString mime;
-    AString type;
-    if (!splitString(codecInfo, " ", &name, &mime, &type)) {
-        return;
-    }
-
-    for (size_t i = 0; i < infos->size(); ++i) {
-        const sp<MediaCodecInfo> &info = infos->itemAt(i);
-        if (name != info->getCodecName()) {
-            continue;
-        }
-
-        Vector<AString> mimes;
-        info->getSupportedMimes(&mimes);
-        for (size_t j = 0; j < mimes.size(); ++j) {
-            if (mimes[j] != mime) {
-                continue;
-            }
-            const sp<MediaCodecInfo::Capabilities> &caps = info->getCapabilitiesFor(mime.c_str());
-            for (size_t k = 0; k < settings.size(); ++k) {
-                caps->getDetails()->setString(
-                        settings.keyAt(k).c_str(), settings.valueAt(k).c_str());
-            }
-        }
-    }
-}
-
-void exportResultsToXML(const char *fileName, const KeyedVector<AString, CodecSettings>& results) {
-#if LOG_NDEBUG == 0
-    ALOGE("measurement results");
+static AString globalResultsToXml(const CodecSettings& results) {
+    AString ret;
     for (size_t i = 0; i < results.size(); ++i) {
-        ALOGE("key %s", results.keyAt(i).c_str());
-        const CodecSettings &settings = results.valueAt(i);
-        for (size_t j = 0; j < settings.size(); ++j) {
-            ALOGE("name %s value %s", settings.keyAt(j).c_str(), settings.valueAt(j).c_str());
-        }
+        AString setting = AStringPrintf(
+                "        <Setting name=\"%s\" value=\"%s\" />\n",
+                results.keyAt(i).c_str(),
+                results.valueAt(i).c_str());
+        ret.append(setting);
     }
-#endif
+    return ret;
+}
 
-    AString overrides;
-    FILE *f = fopen(fileName, "rb");
-    if (f != NULL) {
-        fseek(f, 0, SEEK_END);
-        long size = ftell(f);
-        rewind(f);
-
-        char *buf = (char *)malloc(size);
-        if (fread(buf, size, 1, f) == 1) {
-            overrides.setTo(buf, size);
-            if (!LOG_NDEBUG) {
-                ALOGV("Existing overrides:");
-                printLongString(buf, size);
-            }
-        } else {
-            ALOGE("Failed to read %s", fileName);
-        }
-        fclose(f);
-        free(buf);
-    }
-
+static AString codecResultsToXml(const KeyedVector<AString, CodecSettings>& results) {
+    AString ret;
     for (size_t i = 0; i < results.size(); ++i) {
         AString name;
         AString mime;
-        AString type;
-        if (!splitString(results.keyAt(i), " ", &name, &mime, &type)) {
+        if (!splitString(results.keyAt(i), " ", &name, &mime)) {
             continue;
         }
-        name = AStringPrintf("\"%s\"", name.c_str());
-        mime = AStringPrintf("\"%s\"", mime.c_str());
-        ALOGV("name(%s) mime(%s) type(%s)", name.c_str(), mime.c_str(), type.c_str());
-        ssize_t posCodec = overrides.find(name.c_str());
-        size_t posInsert = 0;
-        if (posCodec < 0) {
-            AString encodersDecoders = (type == "encoder") ? "<Encoders>" : "<Decoders>";
-            AString encodersDecodersEnd = (type == "encoder") ? "</Encoders>" : "</Decoders>";
-            ssize_t posEncodersDecoders = overrides.find(encodersDecoders.c_str());
-            if (posEncodersDecoders < 0) {
-                AString mediaCodecs = "<MediaCodecs>";
-                ssize_t posMediaCodec = overrides.find(mediaCodecs.c_str());
-                if (posMediaCodec < 0) {
-                    posMediaCodec = overrides.size();
-                    overrides.insert("\n<MediaCodecs>\n</MediaCodecs>\n", posMediaCodec);
-                    posMediaCodec = overrides.find(mediaCodecs.c_str(), posMediaCodec);
-                }
-                posEncodersDecoders = posMediaCodec + mediaCodecs.size();
-                AString codecs = AStringPrintf(
-                        "\n    %s\n    %s", encodersDecoders.c_str(), encodersDecodersEnd.c_str());
-                overrides.insert(codecs.c_str(), posEncodersDecoders);
-                posEncodersDecoders = overrides.find(encodersDecoders.c_str(), posEncodersDecoders);
-            }
-            posCodec = posEncodersDecoders + encodersDecoders.size();
-            AString codec = AStringPrintf(
-                        "\n        <MediaCodec name=%s type=%s update=\"true\" >\n        </MediaCodec>",
-                        name.c_str(),
-                        mime.c_str());
-            overrides.insert(codec.c_str(), posCodec);
-            posCodec = overrides.find(name.c_str());
-        }
-
-        // insert to existing entry
-        ssize_t posMime = overrides.find(mime.c_str(), posCodec);
-        ssize_t posEnd = overrides.find(">", posCodec);
-        if (posEnd < 0) {
-            ALOGE("Format error in overrides file.");
-            return;
-        }
-        if (posMime < 0 || posMime > posEnd) {
-            // new mime for an existing component
-            AString codecEnd = "</MediaCodec>";
-            posInsert = overrides.find(codecEnd.c_str(), posCodec) + codecEnd.size();
-            AString codec = AStringPrintf(
-                    "\n        <MediaCodec name=%s type=%s update=\"true\" >\n        </MediaCodec>",
-                    name.c_str(),
-                    mime.c_str());
-            overrides.insert(codec.c_str(), posInsert);
-            posInsert = overrides.find(">", posInsert) + 1;
-        } else {
-            posInsert = posEnd + 1;
-        }
-
+        AString codec =
+                AStringPrintf("        <MediaCodec name=\"%s\" type=\"%s\" update=\"true\" >\n",
+                              name.c_str(),
+                              mime.c_str());
+        ret.append(codec);
         CodecSettings settings = results.valueAt(i);
         for (size_t i = 0; i < settings.size(); ++i) {
             // WARNING: we assume all the settings are "Limit". Currently we have only one type
             // of setting in this case, which is "max-supported-instances".
-            AString strInsert = AStringPrintf(
-                    "\n            <Limit name=\"%s\" value=\"%s\" />",
+            AString setting = AStringPrintf(
+                    "            <Limit name=\"%s\" value=\"%s\" />\n",
                     settings.keyAt(i).c_str(),
                     settings.valueAt(i).c_str());
-            overrides.insert(strInsert, posInsert);
+            ret.append(setting);
         }
+        ret.append("        </MediaCodec>\n");
+    }
+    return ret;
+}
+
+void exportResultsToXML(
+        const char *fileName,
+        const CodecSettings& global_results,
+        const KeyedVector<AString, CodecSettings>& encoder_results,
+        const KeyedVector<AString, CodecSettings>& decoder_results) {
+    if (global_results.size() == 0 && encoder_results.size() == 0 && decoder_results.size() == 0) {
+        return;
     }
 
-    if (!LOG_NDEBUG) {
-        ALOGV("New overrides:");
-        printLongString(overrides.c_str(), overrides.size());
+    AString overrides;
+    overrides.append("<MediaCodecs>\n");
+    if (global_results.size() > 0) {
+        overrides.append("    <Settings>\n");
+        overrides.append(globalResultsToXml(global_results));
+        overrides.append("    </Settings>\n");
     }
+    if (encoder_results.size() > 0) {
+        overrides.append("    <Encoders>\n");
+        overrides.append(codecResultsToXml(encoder_results));
+        overrides.append("    </Encoders>\n");
+    }
+    if (decoder_results.size() > 0) {
+        overrides.append("    <Decoders>\n");
+        overrides.append(codecResultsToXml(decoder_results));
+        overrides.append("    </Decoders>\n");
+    }
+    overrides.append("</MediaCodecs>\n");
 
-    f = fopen(fileName, "wb");
+    FILE *f = fopen(fileName, "wb");
     if (f == NULL) {
         ALOGE("Failed to open %s for writing.", fileName);
         return;
diff --git a/media/libstagefright/MediaCodecListOverrides.h b/media/libstagefright/MediaCodecListOverrides.h
index c6cc2ea..e350d2a 100644
--- a/media/libstagefright/MediaCodecListOverrides.h
+++ b/media/libstagefright/MediaCodecListOverrides.h
@@ -26,24 +26,28 @@
 
 namespace android {
 
+extern const char *kProfilingResults;
+
 struct MediaCodecInfo;
 
 bool splitString(const AString &s, const AString &delimiter, AString *s1, AString *s2);
 
-bool splitString(
-        const AString &s, const AString &delimiter, AString *s1, AString *s2, AString *s3);
+// profile codecs and save the result to xml file named kProfilingResults.
+void profileCodecs(const Vector<sp<MediaCodecInfo>> &infos);
 
+// profile codecs and save the result to global_results, encoder_results and decoder_results.
 void profileCodecs(
         const Vector<sp<MediaCodecInfo>> &infos,
-        KeyedVector<AString, CodecSettings> *results,
-        bool forceToMeasure = false);  // forceToMeasure is mainly for testing
+        CodecSettings *global_results,
+        KeyedVector<AString, CodecSettings> *encoder_results,
+        KeyedVector<AString, CodecSettings> *decoder_results,
+        bool forceToMeasure = false);
 
-void applyCodecSettings(
-        const AString& codecInfo,
-        const CodecSettings &settings,
-        Vector<sp<MediaCodecInfo>> *infos);
-
-void exportResultsToXML(const char *fileName, const KeyedVector<AString, CodecSettings>& results);
+void exportResultsToXML(
+        const char *fileName,
+        const CodecSettings& global_results,
+        const KeyedVector<AString, CodecSettings>& encoder_results,
+        const KeyedVector<AString, CodecSettings>& decoder_results);
 
 }  // namespace android
 
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index d8c38e7..64a8532 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -1503,11 +1503,10 @@
             ALOGV("discarding fetcher-%d", fetcher->getFetcherID());
             fetcher->stopAsync();
         } else {
-            float threshold = -1.0f; // always finish fetching by default
+            float threshold = 0.0f; // default to pause after current block (47Kbytes)
             bool disconnect = false;
             if (timeUs >= 0ll) {
                 // seeking, no need to finish fetching
-                threshold = 0.0f;
                 disconnect = true;
             } else if (delayRemoval) {
                 // adapting, abort if remaining of current segment is over threshold
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index 53087b6..5a0deec 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -1424,11 +1424,17 @@
 
     int64_t minDiffUs, maxDiffUs;
     if (mSeekMode == LiveSession::kSeekModeNextSample) {
+        // if the previous fetcher paused in the middle of a segment, we
+        // want to start at a segment that overlaps the last sample
         minDiffUs = -mPlaylist->getTargetDuration();
         maxDiffUs = 0ll;
     } else {
+        // if the previous fetcher paused at the end of a segment, ideally
+        // we want to start at the segment that's roughly aligned with its
+        // next segment, but if the two variants are not well aligned we
+        // adjust the diff to within (-T/2, T/2)
         minDiffUs = -mPlaylist->getTargetDuration() / 2;
-        maxDiffUs = mPlaylist->getTargetDuration();
+        maxDiffUs = mPlaylist->getTargetDuration() / 2;
     }
 
     int32_t oldSeqNumber = mSeqNumber;
@@ -1611,6 +1617,9 @@
                 ALOGE("MPEG2 Transport streams do not contain subtitles.");
                 return ERROR_MALFORMED;
             }
+            if (stream == LiveSession::STREAMTYPE_METADATA) {
+                continue;
+            }
             ATSParser::SourceType type =LiveSession::getSourceTypeForStream(stream);
             sp<AnotherPacketSource> source =
                 static_cast<AnotherPacketSource *>(
diff --git a/media/libstagefright/tests/MediaCodecListOverrides_test.cpp b/media/libstagefright/tests/MediaCodecListOverrides_test.cpp
index 170cde3..cee62a3 100644
--- a/media/libstagefright/tests/MediaCodecListOverrides_test.cpp
+++ b/media/libstagefright/tests/MediaCodecListOverrides_test.cpp
@@ -31,29 +31,8 @@
 static const char kTestOverridesStr[] =
 "<MediaCodecs>\n"
 "    <Settings>\n"
-"        <Setting name=\"max-max-supported-instances\" value=\"8\" update=\"true\" />\n"
-"    </Settings>\n"
-"    <Encoders>\n"
-"        <MediaCodec name=\"OMX.qcom.video.encoder.mpeg4\" type=\"video/mp4v-es\" update=\"true\" >\n"
-"            <Quirk name=\"requires-allocate-on-input-ports\" />\n"
-"            <Limit name=\"bitrate\" range=\"1-20000000\" />\n"
-"            <Feature name=\"can-swap-width-height\" />\n"
-"        </MediaCodec>\n"
-"    </Encoders>\n"
-"    <Decoders>\n"
-"        <MediaCodec name=\"OMX.qcom.video.decoder.avc\" type=\"video/avc\" update=\"true\" >\n"
-"            <Quirk name=\"requires-allocate-on-input-ports\" />\n"
-"            <Limit name=\"size\" min=\"64x64\" max=\"1920x1088\" />\n"
-"        </MediaCodec>\n"
-"        <MediaCodec name=\"OMX.qcom.video.decoder.mpeg2\" type=\"different_mime\" update=\"true\" >\n"
-"        </MediaCodec>\n"
-"    </Decoders>\n"
-"</MediaCodecs>\n";
-
-static const char kTestOverridesStrNew1[] =
-"<MediaCodecs>\n"
-"    <Settings>\n"
-"        <Setting name=\"max-max-supported-instances\" value=\"8\" update=\"true\" />\n"
+"        <Setting name=\"supports-multiple-secure-codecs\" value=\"false\" />\n"
+"        <Setting name=\"supports-secure-with-non-secure-codec\" value=\"true\" />\n"
 "    </Settings>\n"
 "    <Encoders>\n"
 "        <MediaCodec name=\"OMX.qcom.video.encoder.avc\" type=\"video/avc\" update=\"true\" >\n"
@@ -61,57 +40,21 @@
 "        </MediaCodec>\n"
 "        <MediaCodec name=\"OMX.qcom.video.encoder.mpeg4\" type=\"video/mp4v-es\" update=\"true\" >\n"
 "            <Limit name=\"max-supported-instances\" value=\"4\" />\n"
-"            <Quirk name=\"requires-allocate-on-input-ports\" />\n"
-"            <Limit name=\"bitrate\" range=\"1-20000000\" />\n"
-"            <Feature name=\"can-swap-width-height\" />\n"
 "        </MediaCodec>\n"
 "    </Encoders>\n"
 "    <Decoders>\n"
-"        <MediaCodec name=\"OMX.qcom.video.decoder.mpeg4\" type=\"video/mp4v-es\" update=\"true\" >\n"
-"            <Limit name=\"max-supported-instances\" value=\"3\" />\n"
+"        <MediaCodec name=\"OMX.qcom.video.decoder.avc.secure\" type=\"video/avc\" update=\"true\" >\n"
+"            <Limit name=\"max-supported-instances\" value=\"1\" />\n"
 "        </MediaCodec>\n"
 "        <MediaCodec name=\"OMX.qcom.video.decoder.h263\" type=\"video/3gpp\" update=\"true\" >\n"
 "            <Limit name=\"max-supported-instances\" value=\"4\" />\n"
 "        </MediaCodec>\n"
-"        <MediaCodec name=\"OMX.qcom.video.decoder.avc.secure\" type=\"video/avc\" update=\"true\" >\n"
-"            <Limit name=\"max-supported-instances\" value=\"1\" />\n"
-"        </MediaCodec>\n"
-"        <MediaCodec name=\"OMX.qcom.video.decoder.avc\" type=\"video/avc\" update=\"true\" >\n"
-"            <Quirk name=\"requires-allocate-on-input-ports\" />\n"
-"            <Limit name=\"size\" min=\"64x64\" max=\"1920x1088\" />\n"
-"        </MediaCodec>\n"
-"        <MediaCodec name=\"OMX.qcom.video.decoder.mpeg2\" type=\"different_mime\" update=\"true\" >\n"
-"        </MediaCodec>\n"
 "        <MediaCodec name=\"OMX.qcom.video.decoder.mpeg2\" type=\"video/mpeg2\" update=\"true\" >\n"
 "            <Limit name=\"max-supported-instances\" value=\"3\" />\n"
 "        </MediaCodec>\n"
-"    </Decoders>\n"
-"</MediaCodecs>\n";
-
-static const char kTestOverridesStrNew2[] =
-"\n"
-"<MediaCodecs>\n"
-"    <Encoders>\n"
-"        <MediaCodec name=\"OMX.qcom.video.encoder.mpeg4\" type=\"video/mp4v-es\" update=\"true\" >\n"
-"            <Limit name=\"max-supported-instances\" value=\"4\" />\n"
-"        </MediaCodec>\n"
-"        <MediaCodec name=\"OMX.qcom.video.encoder.avc\" type=\"video/avc\" update=\"true\" >\n"
-"            <Limit name=\"max-supported-instances\" value=\"4\" />\n"
-"        </MediaCodec>\n"
-"    </Encoders>\n"
-"    <Decoders>\n"
 "        <MediaCodec name=\"OMX.qcom.video.decoder.mpeg4\" type=\"video/mp4v-es\" update=\"true\" >\n"
 "            <Limit name=\"max-supported-instances\" value=\"3\" />\n"
 "        </MediaCodec>\n"
-"        <MediaCodec name=\"OMX.qcom.video.decoder.mpeg2\" type=\"video/mpeg2\" update=\"true\" >\n"
-"            <Limit name=\"max-supported-instances\" value=\"3\" />\n"
-"        </MediaCodec>\n"
-"        <MediaCodec name=\"OMX.qcom.video.decoder.h263\" type=\"video/3gpp\" update=\"true\" >\n"
-"            <Limit name=\"max-supported-instances\" value=\"4\" />\n"
-"        </MediaCodec>\n"
-"        <MediaCodec name=\"OMX.qcom.video.decoder.avc.secure\" type=\"video/avc\" update=\"true\" >\n"
-"            <Limit name=\"max-supported-instances\" value=\"1\" />\n"
-"        </MediaCodec>\n"
 "    </Decoders>\n"
 "</MediaCodecs>\n";
 
@@ -119,53 +62,6 @@
 public:
     MediaCodecListOverridesTest() {}
 
-    void verifyOverrides(const KeyedVector<AString, CodecSettings> &overrides) {
-        EXPECT_EQ(3u, overrides.size());
-
-        EXPECT_TRUE(overrides.keyAt(0) == "OMX.qcom.video.decoder.avc video/avc decoder");
-        const CodecSettings &settings0 = overrides.valueAt(0);
-        EXPECT_EQ(1u, settings0.size());
-        EXPECT_TRUE(settings0.keyAt(0) == "max-supported-instances");
-        EXPECT_TRUE(settings0.valueAt(0) == "4");
-
-        EXPECT_TRUE(overrides.keyAt(1) == "OMX.qcom.video.encoder.avc video/avc encoder");
-        const CodecSettings &settings1 = overrides.valueAt(1);
-        EXPECT_EQ(1u, settings1.size());
-        EXPECT_TRUE(settings1.keyAt(0) == "max-supported-instances");
-        EXPECT_TRUE(settings1.valueAt(0) == "3");
-
-        EXPECT_TRUE(overrides.keyAt(2) == "global");
-        const CodecSettings &settings2 = overrides.valueAt(2);
-        EXPECT_EQ(3u, settings2.size());
-        EXPECT_TRUE(settings2.keyAt(0) == "max-max-supported-instances");
-        EXPECT_TRUE(settings2.valueAt(0) == "8");
-        EXPECT_TRUE(settings2.keyAt(1) == "supports-multiple-secure-codecs");
-        EXPECT_TRUE(settings2.valueAt(1) == "false");
-        EXPECT_TRUE(settings2.keyAt(2) == "supports-secure-with-non-secure-codec");
-        EXPECT_TRUE(settings2.valueAt(2) == "true");
-    }
-
-    void verifySetting(const sp<AMessage> &details, const char *name, const char *value) {
-        AString value1;
-        EXPECT_TRUE(details->findString(name, &value1));
-        EXPECT_TRUE(value1 == value);
-    }
-
-    void createTestInfos(Vector<sp<MediaCodecInfo>> *infos) {
-        const char *name = "OMX.qcom.video.decoder.avc";
-        const bool encoder = false;
-        const char *mime = "video/avc";
-        sp<MediaCodecInfo> info = new MediaCodecInfo(name, encoder, mime);
-        infos->push_back(info);
-        const sp<MediaCodecInfo::Capabilities> caps = info->getCapabilitiesFor(mime);
-        const sp<AMessage> details = caps->getDetails();
-        details->setString("cap1", "value1");
-        details->setString("max-max-supported-instances", "16");
-
-        info = new MediaCodecInfo("anothercodec", true, "anothermime");
-        infos->push_back(info);
-    }
-
     void addMaxInstancesSetting(
             const AString &key,
             const AString &value,
@@ -175,16 +71,34 @@
         results->add(key, settings);
     }
 
-    void exportTestResultsToXML(const char *fileName) {
-        KeyedVector<AString, CodecSettings> r;
-        addMaxInstancesSetting("OMX.qcom.video.decoder.avc.secure video/avc decoder", "1", &r);
-        addMaxInstancesSetting("OMX.qcom.video.decoder.h263 video/3gpp decoder", "4", &r);
-        addMaxInstancesSetting("OMX.qcom.video.decoder.mpeg2 video/mpeg2 decoder", "3", &r);
-        addMaxInstancesSetting("OMX.qcom.video.decoder.mpeg4 video/mp4v-es decoder", "3", &r);
-        addMaxInstancesSetting("OMX.qcom.video.encoder.avc video/avc encoder", "4", &r);
-        addMaxInstancesSetting("OMX.qcom.video.encoder.mpeg4 video/mp4v-es encoder", "4", &r);
+    void verifyProfileResults(const KeyedVector<AString, CodecSettings> &results) {
+        EXPECT_LT(0u, results.size());
+        for (size_t i = 0; i < results.size(); ++i) {
+            AString key = results.keyAt(i);
+            CodecSettings settings = results.valueAt(i);
+            EXPECT_EQ(1u, settings.size());
+            EXPECT_TRUE(settings.keyAt(0) == "max-supported-instances");
+            AString valueS = settings.valueAt(0);
+            int32_t value = strtol(valueS.c_str(), NULL, 10);
+            EXPECT_LT(0, value);
+            ALOGV("profileCodecs results %s %s", key.c_str(), valueS.c_str());
+        }
+    }
 
-        exportResultsToXML(fileName, r);
+    void exportTestResultsToXML(const char *fileName) {
+        CodecSettings gR;
+        gR.add("supports-multiple-secure-codecs", "false");
+        gR.add("supports-secure-with-non-secure-codec", "true");
+        KeyedVector<AString, CodecSettings> eR;
+        addMaxInstancesSetting("OMX.qcom.video.encoder.avc video/avc", "4", &eR);
+        addMaxInstancesSetting("OMX.qcom.video.encoder.mpeg4 video/mp4v-es", "4", &eR);
+        KeyedVector<AString, CodecSettings> dR;
+        addMaxInstancesSetting("OMX.qcom.video.decoder.avc.secure video/avc", "1", &dR);
+        addMaxInstancesSetting("OMX.qcom.video.decoder.h263 video/3gpp", "4", &dR);
+        addMaxInstancesSetting("OMX.qcom.video.decoder.mpeg2 video/mpeg2", "3", &dR);
+        addMaxInstancesSetting("OMX.qcom.video.decoder.mpeg4 video/mp4v-es", "3", &dR);
+
+        exportResultsToXML(fileName, gR, eR, dR);
     }
 };
 
@@ -198,18 +112,6 @@
     EXPECT_TRUE(splitString(s, delimiter, &s1, &s2));
     EXPECT_TRUE(s1 == "abc");
     EXPECT_TRUE(s2 == "123");
-
-    s = "abc123xyz";
-    delimiter = ",";
-    AString s3;
-    EXPECT_FALSE(splitString(s, delimiter, &s1, &s2, &s3));
-    s = "abc,123xyz";
-    EXPECT_FALSE(splitString(s, delimiter, &s1, &s2, &s3));
-    s = "abc,123,xyz";
-    EXPECT_TRUE(splitString(s, delimiter, &s1, &s2, &s3));
-    EXPECT_TRUE(s1 == "abc");
-    EXPECT_TRUE(s2 == "123" );
-    EXPECT_TRUE(s3 == "xyz");
 }
 
 // TODO: the codec component never returns OMX_EventCmdComplete in unit test.
@@ -219,76 +121,16 @@
     for (size_t i = 0; i < list->countCodecs(); ++i) {
         infos.push_back(list->getCodecInfo(i));
     }
-    KeyedVector<AString, CodecSettings> results;
-    profileCodecs(infos, &results, true /* forceToMeasure */);
-    EXPECT_LT(0u, results.size());
-    for (size_t i = 0; i < results.size(); ++i) {
-        AString key = results.keyAt(i);
-        CodecSettings settings = results.valueAt(i);
-        EXPECT_EQ(1u, settings.size());
-        EXPECT_TRUE(settings.keyAt(0) == "max-supported-instances");
-        AString valueS = settings.valueAt(0);
-        int32_t value = strtol(valueS.c_str(), NULL, 10);
-        EXPECT_LT(0, value);
-        ALOGV("profileCodecs results %s %s", key.c_str(), valueS.c_str());
-    }
+    CodecSettings global_results;
+    KeyedVector<AString, CodecSettings> encoder_results;
+    KeyedVector<AString, CodecSettings> decoder_results;
+    profileCodecs(
+            infos, &global_results, &encoder_results, &decoder_results, true /* forceToMeasure */);
+    verifyProfileResults(encoder_results);
+    verifyProfileResults(decoder_results);
 }
 
-TEST_F(MediaCodecListOverridesTest, applyCodecSettings) {
-    AString codecInfo = "OMX.qcom.video.decoder.avc video/avc decoder";
-    Vector<sp<MediaCodecInfo>> infos;
-    createTestInfos(&infos);
-    CodecSettings settings;
-    settings.add("max-supported-instances", "3");
-    settings.add("max-max-supported-instances", "8");
-    applyCodecSettings(codecInfo, settings, &infos);
-
-    EXPECT_EQ(2u, infos.size());
-    EXPECT_TRUE(AString(infos[0]->getCodecName()) == "OMX.qcom.video.decoder.avc");
-    const sp<AMessage> details = infos[0]->getCapabilitiesFor("video/avc")->getDetails();
-    verifySetting(details, "max-supported-instances", "3");
-    verifySetting(details, "max-max-supported-instances", "8");
-
-    EXPECT_TRUE(AString(infos[1]->getCodecName()) == "anothercodec");
-    EXPECT_EQ(0u, infos[1]->getCapabilitiesFor("anothermime")->getDetails()->countEntries());
-}
-
-TEST_F(MediaCodecListOverridesTest, exportResultsToExistingFile) {
-    const char *fileName = "/sdcard/mediacodec_list_overrides_test.xml";
-    remove(fileName);
-
-    FILE *f = fopen(fileName, "wb");
-    if (f == NULL) {
-        ALOGW("Failed to open %s for writing.", fileName);
-        return;
-    }
-    EXPECT_EQ(
-            strlen(kTestOverridesStr),
-            fwrite(kTestOverridesStr, 1, strlen(kTestOverridesStr), f));
-    fclose(f);
-
-    exportTestResultsToXML(fileName);
-
-    // verify
-    AString overrides;
-    f = fopen(fileName, "rb");
-    ASSERT_TRUE(f != NULL);
-    fseek(f, 0, SEEK_END);
-    long size = ftell(f);
-    rewind(f);
-
-    char *buf = (char *)malloc(size);
-    EXPECT_EQ((size_t)1, fread(buf, size, 1, f));
-    overrides.setTo(buf, size);
-    fclose(f);
-    free(buf);
-
-    EXPECT_TRUE(overrides == kTestOverridesStrNew1);
-
-    remove(fileName);
-}
-
-TEST_F(MediaCodecListOverridesTest, exportResultsToEmptyFile) {
+TEST_F(MediaCodecListOverridesTest, exportTestResultsToXML) {
     const char *fileName = "/sdcard/mediacodec_list_overrides_test.xml";
     remove(fileName);
 
@@ -308,7 +150,7 @@
     fclose(f);
     free(buf);
 
-    EXPECT_TRUE(overrides == kTestOverridesStrNew2);
+    EXPECT_TRUE(overrides == kTestOverridesStr);
 
     remove(fileName);
 }
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 7040af4..193fd64 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -66,9 +66,9 @@
 #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
 #endif
 
-// Set kUseNewMixer to true to use the new mixer engine always. Otherwise the
-// original code will be used for stereo sinks, the new mixer for multichannel.
-static const bool kUseNewMixer = true;
+// Set kUseNewMixer to true to use the new mixer engine. Otherwise the
+// original code will be used.  This is false for now.
+static const bool kUseNewMixer = false;
 
 // Set kUseFloat to true to allow floating input into the mixer engine.
 // If kUseNewMixer is false, this is ignored or may be overridden internally
diff --git a/services/audiopolicy/enginedefault/Android.mk b/services/audiopolicy/enginedefault/Android.mk
index b0ae835..8d43b89 100755
--- a/services/audiopolicy/enginedefault/Android.mk
+++ b/services/audiopolicy/enginedefault/Android.mk
@@ -43,6 +43,4 @@
     libutils \
     libaudioutils \
 
-include external/stlport/libstlport.mk
-
 include $(BUILD_SHARED_LIBRARY)
diff --git a/services/mediaresourcemanager/Android.mk b/services/mediaresourcemanager/Android.mk
index 84218cf..b72230f 100644
--- a/services/mediaresourcemanager/Android.mk
+++ b/services/mediaresourcemanager/Android.mk
@@ -2,7 +2,7 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := ResourceManagerService.cpp
+LOCAL_SRC_FILES := ResourceManagerService.cpp ServiceLog.cpp
 
 LOCAL_SHARED_LIBRARIES := libmedia libstagefright libbinder libutils liblog
 
@@ -13,6 +13,9 @@
 LOCAL_C_INCLUDES += \
     $(TOPDIR)frameworks/av/include
 
+LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CLANG := true
+
 include $(BUILD_SHARED_LIBRARY)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index 17aac4e..3c093f9 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -29,6 +29,7 @@
 #include <unistd.h>
 
 #include "ResourceManagerService.h"
+#include "ServiceLog.h"
 
 namespace android {
 
@@ -88,7 +89,7 @@
     return infos.editItemAt(infos.size() - 1);
 }
 
-status_t ResourceManagerService::dump(int fd, const Vector<String16>& args) {
+status_t ResourceManagerService::dump(int fd, const Vector<String16>& /* args */) {
     Mutex::Autolock lock(mLock);
 
     String8 result;
@@ -103,16 +104,14 @@
     snprintf(buffer, SIZE, "    SupportsSecureWithNonSecureCodec: %d\n", mSupportsSecureWithNonSecureCodec);
     result.append(buffer);
 
-    snprintf(buffer, SIZE, "  Processes:\n");
-    result.append(buffer);
+    result.append("  Processes:\n");
     for (size_t i = 0; i < mMap.size(); ++i) {
         snprintf(buffer, SIZE, "    Pid: %d\n", mMap.keyAt(i));
         result.append(buffer);
 
         const ResourceInfos &infos = mMap.valueAt(i);
         for (size_t j = 0; j < infos.size(); ++j) {
-            snprintf(buffer, SIZE, "      Client:\n");
-            result.append(buffer);
+            result.append("      Client:\n");
             snprintf(buffer, SIZE, "        Id: %lld\n", (long long)infos[j].clientId);
             result.append(buffer);
 
@@ -120,14 +119,15 @@
             result.append(buffer);
 
             Vector<MediaResource> resources = infos[j].resources;
-            snprintf(buffer, SIZE, "        Resources:\n");
-            result.append(buffer);
+            result.append("        Resources:\n");
             for (size_t k = 0; k < resources.size(); ++k) {
                 snprintf(buffer, SIZE, "          %s\n", resources[k].toString().string());
                 result.append(buffer);
             }
         }
     }
+    result.append("  Logs:\n");
+    result.append(mServiceLog->toString());
 
     write(fd, result.string(), result.size());
     return OK;
@@ -135,27 +135,30 @@
 
 ResourceManagerService::ResourceManagerService()
     : mProcessInfo(new ProcessInfo()),
+      mServiceLog(new ServiceLog()),
       mSupportsMultipleSecureCodecs(true),
       mSupportsSecureWithNonSecureCodec(true) {}
 
 ResourceManagerService::ResourceManagerService(sp<ProcessInfoInterface> processInfo)
     : mProcessInfo(processInfo),
+      mServiceLog(new ServiceLog()),
       mSupportsMultipleSecureCodecs(true),
       mSupportsSecureWithNonSecureCodec(true) {}
 
 ResourceManagerService::~ResourceManagerService() {}
 
 void ResourceManagerService::config(const Vector<MediaResourcePolicy> &policies) {
-    ALOGV("config(%s)", getString(policies).string());
+    String8 log = String8::format("config(%s)", getString(policies).string());
+    mServiceLog->add(log);
 
     Mutex::Autolock lock(mLock);
     for (size_t i = 0; i < policies.size(); ++i) {
         String8 type = policies[i].mType;
-        uint64_t value = policies[i].mValue;
+        String8 value = policies[i].mValue;
         if (type == kPolicySupportsMultipleSecureCodecs) {
-            mSupportsMultipleSecureCodecs = (value != 0);
+            mSupportsMultipleSecureCodecs = (value == "true");
         } else if (type == kPolicySupportsSecureWithNonSecureCodec) {
-            mSupportsSecureWithNonSecureCodec = (value != 0);
+            mSupportsSecureWithNonSecureCodec = (value == "true");
         }
     }
 }
@@ -165,8 +168,9 @@
         int64_t clientId,
         const sp<IResourceManagerClient> client,
         const Vector<MediaResource> &resources) {
-    ALOGV("addResource(pid %d, clientId %lld, resources %s)",
+    String8 log = String8::format("addResource(pid %d, clientId %lld, resources %s)",
             pid, (long long) clientId, getString(resources).string());
+    mServiceLog->add(log);
 
     Mutex::Autolock lock(mLock);
     ResourceInfos& infos = getResourceInfosForEdit(pid, mMap);
@@ -176,7 +180,8 @@
 }
 
 void ResourceManagerService::removeResource(int64_t clientId) {
-    ALOGV("removeResource(%lld)", (long long) clientId);
+    String8 log = String8::format("removeResource(%lld)", (long long) clientId);
+    mServiceLog->add(log);
 
     Mutex::Autolock lock(mLock);
     bool found = false;
@@ -201,8 +206,9 @@
 
 bool ResourceManagerService::reclaimResource(
         int callingPid, const Vector<MediaResource> &resources) {
-    ALOGV("reclaimResource(callingPid %d, resources %s)",
+    String8 log = String8::format("reclaimResource(callingPid %d, resources %s)",
             callingPid, getString(resources).string());
+    mServiceLog->add(log);
 
     Vector<sp<IResourceManagerClient>> clients;
     {
@@ -265,7 +271,8 @@
 
     sp<IResourceManagerClient> failedClient;
     for (size_t i = 0; i < clients.size(); ++i) {
-        ALOGV("reclaimResource from client %p", clients[i].get());
+        log = String8::format("reclaimResource from client %p", clients[i].get());
+        mServiceLog->add(log);
         if (!clients[i]->reclaimResource()) {
             failedClient = clients[i];
             break;
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index 0c3d694..0d9d878 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -30,6 +30,7 @@
 
 namespace android {
 
+class ServiceLog;
 struct ProcessInfoInterface;
 
 struct ResourceInfo {
@@ -96,6 +97,7 @@
 
     mutable Mutex mLock;
     sp<ProcessInfoInterface> mProcessInfo;
+    sp<ServiceLog> mServiceLog;
     PidResourceInfosMap mMap;
     bool mSupportsMultipleSecureCodecs;
     bool mSupportsSecureWithNonSecureCodec;
diff --git a/services/mediaresourcemanager/ServiceLog.cpp b/services/mediaresourcemanager/ServiceLog.cpp
new file mode 100644
index 0000000..be7b308
--- /dev/null
+++ b/services/mediaresourcemanager/ServiceLog.cpp
@@ -0,0 +1,54 @@
+/*
+**
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ServiceLog"
+#include <utils/Log.h>
+
+#include <time.h>
+
+#include "ServiceLog.h"
+
+static const size_t kDefaultMaxNum = 100;
+
+namespace android {
+
+ServiceLog::ServiceLog() : mMaxNum(kDefaultMaxNum) {}
+ServiceLog::ServiceLog(size_t maxNum) : mMaxNum(maxNum) {}
+
+void ServiceLog::add(const String8 &log) {
+    Mutex::Autolock lock(mLock);
+    time_t now = time(0);
+    char buf[64];
+    strftime(buf, sizeof(buf), "%m-%d %T", localtime(&now));
+    String8 formattedLog = String8::format("%s %s", buf, log.string());
+    if (mLogs.add(formattedLog) == mMaxNum) {
+        mLogs.removeAt(0);
+    }
+}
+
+String8 ServiceLog::toString() const {
+    Mutex::Autolock lock(mLock);
+    String8 result;
+    for (size_t i = 0; i < mLogs.size(); ++i) {
+        result.append(mLogs[i]);
+        result.append("\n");
+    }
+    return result;
+}
+
+} // namespace android
diff --git a/services/mediaresourcemanager/ServiceLog.h b/services/mediaresourcemanager/ServiceLog.h
new file mode 100644
index 0000000..14814ff
--- /dev/null
+++ b/services/mediaresourcemanager/ServiceLog.h
@@ -0,0 +1,46 @@
+/*
+**
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ANDROID_SERVICELOG_H
+#define ANDROID_SERVICELOG_H
+
+#include <utils/Errors.h>
+#include <utils/String8.h>
+#include <utils/threads.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+class ServiceLog : public RefBase {
+public:
+    ServiceLog();
+    ServiceLog(size_t maxNum);
+
+    void add(const String8 &log);
+    String8 toString() const;
+
+private:
+    int mMaxNum;
+    mutable Mutex mLock;
+    Vector<String8> mLogs;
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_SERVICELOG_H
diff --git a/services/mediaresourcemanager/test/Android.mk b/services/mediaresourcemanager/test/Android.mk
index 228b62a..3b4ef0d 100644
--- a/services/mediaresourcemanager/test/Android.mk
+++ b/services/mediaresourcemanager/test/Android.mk
@@ -20,6 +20,35 @@
   frameworks/av/include \
   frameworks/av/services/mediaresourcemanager \
 
+LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CLANG := true
+
+LOCAL_32_BIT_ONLY := true
+
+include $(BUILD_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := ServiceLog_test
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := \
+  ServiceLog_test.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+  liblog \
+  libmedia \
+  libresourcemanagerservice \
+  libutils \
+
+LOCAL_C_INCLUDES := \
+  frameworks/av/include \
+  frameworks/av/services/mediaresourcemanager \
+
+LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CLANG := true
+
 LOCAL_32_BIT_ONLY := true
 
 include $(BUILD_NATIVE_TEST)
diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
index bccc7fa..3d53f1f 100644
--- a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
@@ -180,17 +180,27 @@
         EXPECT_TRUE(mService->mSupportsSecureWithNonSecureCodec);
 
         Vector<MediaResourcePolicy> policies1;
-        policies1.push_back(MediaResourcePolicy(String8(kPolicySupportsMultipleSecureCodecs), 1));
         policies1.push_back(
-                MediaResourcePolicy(String8(kPolicySupportsSecureWithNonSecureCodec), 0));
+                MediaResourcePolicy(
+                        String8(kPolicySupportsMultipleSecureCodecs),
+                        String8("true")));
+        policies1.push_back(
+                MediaResourcePolicy(
+                        String8(kPolicySupportsSecureWithNonSecureCodec),
+                        String8("false")));
         mService->config(policies1);
         EXPECT_TRUE(mService->mSupportsMultipleSecureCodecs);
         EXPECT_FALSE(mService->mSupportsSecureWithNonSecureCodec);
 
         Vector<MediaResourcePolicy> policies2;
-        policies2.push_back(MediaResourcePolicy(String8(kPolicySupportsMultipleSecureCodecs), 0));
         policies2.push_back(
-                MediaResourcePolicy(String8(kPolicySupportsSecureWithNonSecureCodec), 1));
+                MediaResourcePolicy(
+                        String8(kPolicySupportsMultipleSecureCodecs),
+                        String8("false")));
+        policies2.push_back(
+                MediaResourcePolicy(
+                        String8(kPolicySupportsSecureWithNonSecureCodec),
+                        String8("true")));
         mService->config(policies2);
         EXPECT_FALSE(mService->mSupportsMultipleSecureCodecs);
         EXPECT_TRUE(mService->mSupportsSecureWithNonSecureCodec);
diff --git a/services/mediaresourcemanager/test/ServiceLog_test.cpp b/services/mediaresourcemanager/test/ServiceLog_test.cpp
new file mode 100644
index 0000000..6ddcb87
--- /dev/null
+++ b/services/mediaresourcemanager/test/ServiceLog_test.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ServiceLog_test"
+#include <utils/Log.h>
+
+#include <gtest/gtest.h>
+
+#include "ServiceLog.h"
+
+namespace android {
+
+class ServiceLogTest : public ::testing::Test {
+public:
+    ServiceLogTest() : mServiceLog(new ServiceLog(3)) {
+    }
+
+protected:
+    sp<ServiceLog> mServiceLog;
+};
+
+TEST_F(ServiceLogTest, addThenToString) {
+    mServiceLog->add(String8("log1"));
+    EXPECT_TRUE(mServiceLog->toString().contains("log1"));
+    ALOGV("toString:\n%s", mServiceLog->toString().string());
+
+    mServiceLog->add(String8("log2"));
+    EXPECT_TRUE(mServiceLog->toString().contains("log1"));
+    EXPECT_TRUE(mServiceLog->toString().contains("log2"));
+    ALOGV("toString:\n%s", mServiceLog->toString().string());
+
+    mServiceLog->add(String8("log3"));
+    EXPECT_TRUE(mServiceLog->toString().contains("log1"));
+    EXPECT_TRUE(mServiceLog->toString().contains("log2"));
+    EXPECT_TRUE(mServiceLog->toString().contains("log3"));
+    ALOGV("toString:\n%s", mServiceLog->toString().string());
+
+    mServiceLog->add(String8("log4"));
+    EXPECT_FALSE(mServiceLog->toString().contains("log1"));
+    EXPECT_TRUE(mServiceLog->toString().contains("log2"));
+    EXPECT_TRUE(mServiceLog->toString().contains("log3"));
+    EXPECT_TRUE(mServiceLog->toString().contains("log4"));
+    ALOGV("toString:\n%s", mServiceLog->toString().string());
+
+    mServiceLog->add(String8("log5"));
+    EXPECT_FALSE(mServiceLog->toString().contains("log1"));
+    EXPECT_FALSE(mServiceLog->toString().contains("log2"));
+    EXPECT_TRUE(mServiceLog->toString().contains("log3"));
+    EXPECT_TRUE(mServiceLog->toString().contains("log4"));
+    EXPECT_TRUE(mServiceLog->toString().contains("log5"));
+    ALOGV("toString:\n%s", mServiceLog->toString().string());
+}
+
+} // namespace android