Merge "Camera: Clear cached HIDL references"
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index c62833d..c7619af 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -111,7 +111,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
         libstagefright liblog libutils libbinder libui libgui \
-        libstagefright_foundation libmedia libcutils
+        libstagefright_foundation libmedia libcutils libmediaextractor
 
 LOCAL_C_INCLUDES:= \
         frameworks/av/media/libstagefright \
@@ -204,7 +204,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
         libstagefright liblog libutils libbinder libstagefright_foundation \
-        libcutils libc
+        libcutils libc libmediaextractor
 
 LOCAL_C_INCLUDES:= \
         frameworks/av/media/libstagefright \
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index b5c1ddf..07cec01 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -252,9 +252,9 @@
 
 void DrmHal::closeOpenSessions() {
     if (mPlugin != NULL) {
-        auto openSessions = mOpenSessions;
-        for (size_t i = 0; i < openSessions.size(); i++) {
-            closeSession(openSessions[i]);
+        for (size_t i = 0; i < mOpenSessions.size(); i++) {
+            mPlugin->closeSession(toHidlVec(mOpenSessions[i]));
+            DrmSessionManager::Instance()->removeSession(mOpenSessions[i]);
         }
     }
     mOpenSessions.clear();
@@ -472,7 +472,9 @@
     for (size_t i = 0; i < mFactories.size(); i++) {
         if (mFactories[i]->isCryptoSchemeSupported(uuid)) {
             mPlugin = makeDrmPlugin(mFactories[i], uuid, appPackageName);
-            mPluginV1_1 = drm::V1_1::IDrmPlugin::castFrom(mPlugin);
+            if (mPlugin != NULL) {
+                mPluginV1_1 = drm::V1_1::IDrmPlugin::castFrom(mPlugin);
+            }
         }
     }
 
@@ -504,6 +506,7 @@
         }
     }
     mPlugin.clear();
+    mPluginV1_1.clear();
     return OK;
 }
 
diff --git a/drm/libmediadrm/PluginMetricsReporting.cpp b/drm/libmediadrm/PluginMetricsReporting.cpp
index cc7fb72..26c8427 100644
--- a/drm/libmediadrm/PluginMetricsReporting.cpp
+++ b/drm/libmediadrm/PluginMetricsReporting.cpp
@@ -80,7 +80,6 @@
         }
     }
 
-    analyticsItem.setFinalized(true);
     if (!analyticsItem.selfrecord()) {
       ALOGE("selfrecord() returned false. sessioId %" PRId64, sessionId);
     }
diff --git a/media/extractors/aac/AACExtractor.cpp b/media/extractors/aac/AACExtractor.cpp
index 17d6aee..6f28374 100644
--- a/media/extractors/aac/AACExtractor.cpp
+++ b/media/extractors/aac/AACExtractor.cpp
@@ -21,7 +21,6 @@
 #include "AACExtractor.h"
 #include <media/DataSource.h>
 #include <media/MediaSourceBase.h>
-#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -29,6 +28,7 @@
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
+#include <media/stagefright/MetaDataUtils.h>
 #include <utils/String8.h>
 
 namespace android {
diff --git a/media/extractors/aac/Android.bp b/media/extractors/aac/Android.bp
index 7937a29..92575f2 100644
--- a/media/extractors/aac/Android.bp
+++ b/media/extractors/aac/Android.bp
@@ -13,6 +13,10 @@
         "libutils",
     ],
 
+    static_libs: [
+        "libstagefright_metadatautils",
+    ],
+
     name: "libaacextractor",
     relative_install_path: "extractors",
 
diff --git a/media/extractors/mkv/Android.bp b/media/extractors/mkv/Android.bp
index 0301ffa..c6cd753 100644
--- a/media/extractors/mkv/Android.bp
+++ b/media/extractors/mkv/Android.bp
@@ -18,6 +18,7 @@
 
     static_libs: [
         "libstagefright_flacdec",
+        "libstagefright_metadatautils",
         "libwebm",
     ],
 
diff --git a/media/extractors/mkv/MatroskaExtractor.cpp b/media/extractors/mkv/MatroskaExtractor.cpp
index 7baccb7..6df0012 100644
--- a/media/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/extractors/mkv/MatroskaExtractor.cpp
@@ -28,12 +28,12 @@
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ByteUtils.h>
 #include <media/stagefright/foundation/ColorUtils.h>
-#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
+#include <media/stagefright/MetaDataUtils.h>
 #include <utils/String8.h>
 
 #include <inttypes.h>
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index e88a464..9f21db6 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -602,6 +602,14 @@
                 ALOGE("heif image %u has no meta!", imageIndex);
                 continue;
             }
+            // Some heif files advertise image sequence brands (eg. 'hevc') in
+            // ftyp box, but don't have any valid tracks in them. Instead of
+            // reporting the entire file as malformed, we override the error
+            // to allow still images to be extracted.
+            if (err != OK) {
+                ALOGW("Extracting still images only");
+                err = OK;
+            }
 
             ALOGV("adding HEIF image track %u", imageIndex);
             Track *track = new Track;
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 3aebb8a..6b3a8f0 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -1316,6 +1316,14 @@
     }
 }
 
+// -------------------------------------------------------------------------
+
+status_t AudioRecord::getActiveMicrophones(std::vector<media::MicrophoneInfo>* activeMicrophones)
+{
+    AutoMutex lock(mLock);
+    return mAudioRecord->getActiveMicrophones(activeMicrophones).transactionError();
+}
+
 // =========================================================================
 
 void AudioRecord::DeathNotifier::binderDied(const wp<IBinder>& who __unused)
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index b6c98cc..3358e35 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -24,6 +24,7 @@
 
 #include <binder/IPCThreadState.h>
 #include <binder/Parcel.h>
+#include <private/android_filesystem_config.h>
 
 #include "IAudioFlinger.h"
 
@@ -894,6 +895,24 @@
             break;
     }
 
+    // make sure the following transactions come from system components
+    switch (code) {
+        case SET_MASTER_VOLUME:
+        case SET_MASTER_MUTE:
+        case SET_MODE:
+        case SET_MIC_MUTE:
+        case SET_LOW_RAM_DEVICE:
+        case SYSTEM_READY:
+            if (IPCThreadState::self()->getCallingUid() >= AID_APP_START) {
+                ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
+                      __func__, code, IPCThreadState::self()->getCallingPid(),
+                      IPCThreadState::self()->getCallingUid());
+                return INVALID_OPERATION;
+            }
+        default:
+            break;
+    }
+
     // Whitelist of relevant events to trigger log merging.
     // Log merging should activate during audio activity of any kind. This are considered the
     // most relevant events.
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index 6478975..a24a099 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -27,7 +27,7 @@
 
 #include <media/AudioEffect.h>
 #include <media/IAudioPolicyService.h>
-
+#include <private/android_filesystem_config.h>
 #include <system/audio.h>
 
 namespace android {
@@ -869,6 +869,27 @@
             break;
     }
 
+    // make sure the following transactions come from system components
+    switch (code) {
+        case SET_DEVICE_CONNECTION_STATE:
+        case HANDLE_DEVICE_CONFIG_CHANGE:
+        case SET_PHONE_STATE:
+        case SET_RINGER_MODE:
+        case SET_FORCE_USE:
+        case INIT_STREAM_VOLUME:
+        case SET_STREAM_VOLUME:
+        case REGISTER_POLICY_MIXES:
+        case SET_MASTER_MONO:
+            if (IPCThreadState::self()->getCallingUid() >= AID_APP_START) {
+                ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
+                      __func__, code, IPCThreadState::self()->getCallingPid(),
+                      IPCThreadState::self()->getCallingUid());
+                return INVALID_OPERATION;
+            }
+        default:
+            break;
+    }
+
     switch (code) {
         case SET_DEVICE_CONNECTION_STATE: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
diff --git a/media/libaudioclient/aidl/android/media/IAudioRecord.aidl b/media/libaudioclient/aidl/android/media/IAudioRecord.aidl
index 7572671..01e0a71 100644
--- a/media/libaudioclient/aidl/android/media/IAudioRecord.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioRecord.aidl
@@ -16,6 +16,8 @@
 
 package android.media;
 
+import android.media.MicrophoneInfo;
+
 /* Native code must specify namespace media (media::IAudioRecord) when referring to this class */
 interface IAudioRecord {
 
@@ -30,4 +32,8 @@
    * will be processed, unless flush() is called.
    */
   void stop();
+
+  /* Get a list of current active microphones.
+   */
+  void getActiveMicrophones(out MicrophoneInfo[] activeMicrophones);
 }
diff --git a/media/libaudioclient/include/media/AudioRecord.h b/media/libaudioclient/include/media/AudioRecord.h
index caaefce..c07c397 100644
--- a/media/libaudioclient/include/media/AudioRecord.h
+++ b/media/libaudioclient/include/media/AudioRecord.h
@@ -23,8 +23,10 @@
 #include <media/AudioTimestamp.h>
 #include <media/MediaAnalyticsItem.h>
 #include <media/Modulo.h>
+#include <media/MicrophoneInfo.h>
 #include <utils/RefBase.h>
 #include <utils/threads.h>
+#include <vector>
 
 #include "android/media/IAudioRecord.h"
 
@@ -527,6 +529,11 @@
     /* Get the flags */
             audio_input_flags_t getFlags() const { AutoMutex _l(mLock); return mFlags; }
 
+    /* Get active microphones. A empty vector of MicrophoneInfo will be passed as a parameter,
+     * the data will be filled when querying the hal.
+     */
+            status_t    getActiveMicrophones(std::vector<media::MicrophoneInfo>* activeMicrophones);
+
     /*
      * Dumps the state of an audio record.
      */
@@ -703,7 +710,6 @@
             // mAnalyticsItem alloc failure will be flagged in the constructor
             // don't log empty records
             if (mAnalyticsItem->count() > 0) {
-                mAnalyticsItem->setFinalized(true);
                 mAnalyticsItem->selfrecord();
             }
         }
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index 8fbe980..e5bb854 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -1198,7 +1198,6 @@
             // mAnalyticsItem alloc failure will be flagged in the constructor
             // don't log empty records
             if (mAnalyticsItem->count() > 0) {
-                mAnalyticsItem->setFinalized(true);
                 mAnalyticsItem->selfrecord();
             }
         }
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 28684da..1377005 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -318,9 +318,7 @@
 
     srcs: [
         "JAudioTrack.cpp",
-        "MediaPlayer2Factory.cpp",
         "MediaPlayer2Manager.cpp",
-        "TestPlayerStub.cpp",
         "mediaplayer2.cpp",
     ],
 
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
index 72f5f58..b2c91c4 100644
--- a/media/libmedia/IMediaRecorder.cpp
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -64,6 +64,7 @@
     SET_INPUT_DEVICE,
     GET_ROUTED_DEVICE_ID,
     ENABLE_AUDIO_DEVICE_CALLBACK,
+    GET_ACTIVE_MICROPHONES,
 
 };
 
@@ -391,6 +392,21 @@
         }
         return reply.readInt32();
     }
+
+    status_t getActiveMicrophones(std::vector<media::MicrophoneInfo>* activeMicrophones)
+    {
+        ALOGV("getActiveMicrophones");
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        status_t status = remote()->transact(GET_ACTIVE_MICROPHONES, data, &reply);
+        if (status != OK
+                || (status = (status_t)reply.readInt32()) != NO_ERROR) {
+            return status;
+        }
+        status = reply.readParcelableVector(activeMicrophones);
+        return status;
+    }
+
 };
 
 IMPLEMENT_META_INTERFACE(MediaRecorder, "android.media.IMediaRecorder");
@@ -631,6 +647,19 @@
                 reply->writeInt32(BAD_VALUE);
             }
             return NO_ERROR;
+        } break;
+        case GET_ACTIVE_MICROPHONES: {
+            ALOGV("GET_ACTIVE_MICROPHONES");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            std::vector<media::MicrophoneInfo> activeMicrophones;
+            status_t status = getActiveMicrophones(&activeMicrophones);
+            reply->writeInt32(status);
+            if (status != NO_ERROR) {
+                return NO_ERROR;
+            }
+            reply->writeParcelableVector(activeMicrophones);
+            return NO_ERROR;
+
         }
         default:
             return BBinder::onTransact(code, data, reply, flags);
diff --git a/media/libmedia/MediaPlayer2Factory.cpp b/media/libmedia/MediaPlayer2Factory.cpp
deleted file mode 100644
index ac115f6..0000000
--- a/media/libmedia/MediaPlayer2Factory.cpp
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
-**
-** Copyright 2017, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "MediaPlayer2Factory"
-#include <utils/Log.h>
-
-#include <cutils/properties.h>
-#include <media/DataSource.h>
-#include <media/MediaPlayer2Engine.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <utils/Errors.h>
-#include <utils/misc.h>
-
-#include "MediaPlayer2Factory.h"
-
-#include "TestPlayerStub.h"
-#include "nuplayer2/NuPlayer2Driver.h"
-
-namespace android {
-
-Mutex MediaPlayer2Factory::sLock;
-MediaPlayer2Factory::tFactoryMap *MediaPlayer2Factory::sFactoryMap;
-bool MediaPlayer2Factory::sInitComplete = false;
-
-// static
-bool MediaPlayer2Factory::ensureInit_l() {
-    if (sFactoryMap == NULL) {
-        sFactoryMap = new (std::nothrow) tFactoryMap();
-    }
-    return (sFactoryMap != NULL);
-}
-
-status_t MediaPlayer2Factory::registerFactory_l(IFactory* factory,
-                                                player2_type type) {
-    if (NULL == factory) {
-        ALOGE("Failed to register MediaPlayer2Factory of type %d, factory is"
-              " NULL.", type);
-        return BAD_VALUE;
-    }
-
-    if (!ensureInit_l()) {
-        return NO_INIT;
-    }
-
-    if (sFactoryMap->indexOfKey(type) >= 0) {
-        ALOGE("Failed to register MediaPlayer2Factory of type %d, type is"
-              " already registered.", type);
-        return ALREADY_EXISTS;
-    }
-
-    if (sFactoryMap->add(type, factory) < 0) {
-        ALOGE("Failed to register MediaPlayer2Factory of type %d, failed to add"
-              " to map.", type);
-        return UNKNOWN_ERROR;
-    }
-
-    return OK;
-}
-
-static player2_type getDefaultPlayerType() {
-    return PLAYER2_NU_PLAYER2;
-}
-
-#define GET_PLAYER_TYPE_IMPL(a...)                      \
-    Mutex::Autolock lock_(&sLock);                      \
-                                                        \
-    player2_type ret = PLAYER2_STAGEFRIGHT_PLAYER;      \
-    float bestScore = 0.0;                              \
-                                                        \
-    if (!ensureInit_l()) {                              \
-        return ret;                                     \
-    }                                                   \
-                                                        \
-    for (size_t i = 0; i < sFactoryMap->size(); ++i) {  \
-                                                        \
-        IFactory* v = sFactoryMap->valueAt(i);          \
-        float thisScore;                                \
-        CHECK(v != NULL);                               \
-        thisScore = v->scoreFactory(a, bestScore);      \
-        if (thisScore > bestScore) {                    \
-            ret = sFactoryMap->keyAt(i);                \
-            bestScore = thisScore;                      \
-        }                                               \
-    }                                                   \
-                                                        \
-    if (0.0 == bestScore) {                             \
-        ret = getDefaultPlayerType();                   \
-    }                                                   \
-                                                        \
-    return ret;
-
-player2_type MediaPlayer2Factory::getPlayerType(const sp<MediaPlayer2Engine>& client,
-                                               const char* url) {
-    GET_PLAYER_TYPE_IMPL(client, url);
-}
-
-player2_type MediaPlayer2Factory::getPlayerType(const sp<MediaPlayer2Engine>& client,
-                                                int fd,
-                                                int64_t offset,
-                                                int64_t length) {
-    GET_PLAYER_TYPE_IMPL(client, fd, offset, length);
-}
-
-player2_type MediaPlayer2Factory::getPlayerType(const sp<MediaPlayer2Engine>& client,
-                                                const sp<IStreamSource> &source) {
-    GET_PLAYER_TYPE_IMPL(client, source);
-}
-
-player2_type MediaPlayer2Factory::getPlayerType(const sp<MediaPlayer2Engine>& client,
-                                                const sp<DataSource> &source) {
-    GET_PLAYER_TYPE_IMPL(client, source);
-}
-
-#undef GET_PLAYER_TYPE_IMPL
-
-sp<MediaPlayer2Base> MediaPlayer2Factory::createPlayer(
-        player2_type playerType,
-        const wp<MediaPlayer2Engine> &client,
-        MediaPlayer2Base::NotifyCallback notifyFunc,
-        pid_t pid) {
-    sp<MediaPlayer2Base> p;
-    IFactory* factory;
-    status_t init_result;
-    Mutex::Autolock lock_(&sLock);
-
-    if (!ensureInit_l()) {
-        return NULL;
-    }
-
-    if (sFactoryMap->indexOfKey(playerType) < 0) {
-        ALOGE("Failed to create player object of type %d, no registered"
-              " factory", playerType);
-        return p;
-    }
-
-    factory = sFactoryMap->valueFor(playerType);
-    CHECK(NULL != factory);
-    p = factory->createPlayer(pid);
-
-    if (p == NULL) {
-        ALOGE("Failed to create player object of type %d, create failed",
-              playerType);
-        return p;
-    }
-
-    init_result = p->initCheck();
-    if (init_result == NO_ERROR) {
-        p->setNotifyCallback(client, notifyFunc);
-    } else {
-        ALOGE("Failed to create player object of type %d, initCheck failed"
-              " (res = %d)", playerType, init_result);
-        p.clear();
-    }
-
-    return p;
-}
-
-/*****************************************************************************
- *                                                                           *
- *                     Built-In Factory Implementations                      *
- *                                                                           *
- *****************************************************************************/
-
-class NuPlayer2Factory : public MediaPlayer2Factory::IFactory {
-  public:
-    virtual float scoreFactory(const sp<MediaPlayer2Engine>& /*client*/,
-                               const char* url,
-                               float curScore) {
-        static const float kOurScore = 0.8;
-
-        if (kOurScore <= curScore) {
-            return 0.0;
-        }
-
-        if (!strncasecmp("http://", url, 7)
-                || !strncasecmp("https://", url, 8)
-                || !strncasecmp("file://", url, 7)) {
-            size_t len = strlen(url);
-            if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {
-                return kOurScore;
-            }
-
-            if (strstr(url,"m3u8")) {
-                return kOurScore;
-            }
-
-            if ((len >= 4 && !strcasecmp(".sdp", &url[len - 4])) || strstr(url, ".sdp?")) {
-                return kOurScore;
-            }
-        }
-
-        if (!strncasecmp("rtsp://", url, 7)) {
-            return kOurScore;
-        }
-
-        return 0.0;
-    }
-
-    virtual float scoreFactory(const sp<MediaPlayer2Engine>& /*client*/,
-                               const sp<IStreamSource>& /*source*/,
-                               float /*curScore*/) {
-        return 1.0;
-    }
-
-    virtual float scoreFactory(const sp<MediaPlayer2Engine>& /*client*/,
-                               const sp<DataSource>& /*source*/,
-                               float /*curScore*/) {
-        // Only NuPlayer2 supports setting a DataSource source directly.
-        return 1.0;
-    }
-
-    virtual sp<MediaPlayer2Base> createPlayer(pid_t pid) {
-        ALOGV(" create NuPlayer2");
-        return new NuPlayer2Driver(pid);
-    }
-};
-
-class TestPlayerFactory : public MediaPlayer2Factory::IFactory {
-  public:
-    virtual float scoreFactory(const sp<MediaPlayer2Engine>& /*client*/,
-                               const char* url,
-                               float /*curScore*/) {
-        if (TestPlayerStub::canBeUsed(url)) {
-            return 1.0;
-        }
-
-        return 0.0;
-    }
-
-    virtual sp<MediaPlayer2Base> createPlayer(pid_t /* pid */) {
-        ALOGV("Create Test Player stub");
-        return new TestPlayerStub();
-    }
-};
-
-void MediaPlayer2Factory::registerBuiltinFactories() {
-    Mutex::Autolock lock_(&sLock);
-
-    if (sInitComplete) {
-        return;
-    }
-
-    IFactory* factory = new NuPlayer2Factory();
-    if (registerFactory_l(factory, PLAYER2_NU_PLAYER2) != OK) {
-        delete factory;
-    }
-    factory = new TestPlayerFactory();
-    if (registerFactory_l(factory, PLAYER2_TEST_PLAYER) != OK) {
-        delete factory;
-    }
-
-    sInitComplete = true;
-}
-
-}  // namespace android
diff --git a/media/libmedia/MediaPlayer2Factory.h b/media/libmedia/MediaPlayer2Factory.h
deleted file mode 100644
index 416d241..0000000
--- a/media/libmedia/MediaPlayer2Factory.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
-**
-** Copyright 2017, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#ifndef ANDROID_MEDIAPLAYER2FACTORY_H
-#define ANDROID_MEDIAPLAYER2FACTORY_H
-
-#include <media/MediaPlayer2Interface.h>
-#include <media/stagefright/foundation/ABase.h>
-
-namespace android {
-
-class MediaPlayer2Factory {
-  public:
-    class IFactory {
-      public:
-        virtual ~IFactory() { }
-
-        virtual float scoreFactory(const sp<MediaPlayer2Engine>& /*client*/,
-                                   const char* /*url*/,
-                                   float /*curScore*/) { return 0.0; }
-
-        virtual float scoreFactory(const sp<MediaPlayer2Engine>& /*client*/,
-                                   int /*fd*/,
-                                   int64_t /*offset*/,
-                                   int64_t /*length*/,
-                                   float /*curScore*/) { return 0.0; }
-
-        virtual float scoreFactory(const sp<MediaPlayer2Engine>& /*client*/,
-                                   const sp<IStreamSource> &/*source*/,
-                                   float /*curScore*/) { return 0.0; }
-
-        virtual float scoreFactory(const sp<MediaPlayer2Engine>& /*client*/,
-                                   const sp<DataSource> &/*source*/,
-                                   float /*curScore*/) { return 0.0; }
-
-        virtual sp<MediaPlayer2Base> createPlayer(pid_t pid) = 0;
-    };
-
-    static player2_type getPlayerType(const sp<MediaPlayer2Engine>& client,
-                                      const char* url);
-    static player2_type getPlayerType(const sp<MediaPlayer2Engine>& client,
-                                      int fd,
-                                      int64_t offset,
-                                      int64_t length);
-    static player2_type getPlayerType(const sp<MediaPlayer2Engine>& client,
-                                      const sp<IStreamSource> &source);
-    static player2_type getPlayerType(const sp<MediaPlayer2Engine>& client,
-                                      const sp<DataSource> &source);
-
-    static sp<MediaPlayer2Base> createPlayer(player2_type playerType,
-                                             const wp<MediaPlayer2Engine> &client,
-                                             MediaPlayer2Base::NotifyCallback notifyFunc,
-                                             pid_t pid);
-
-    static void registerBuiltinFactories();
-
-  private:
-    typedef KeyedVector<player2_type, IFactory*> tFactoryMap;
-
-    MediaPlayer2Factory() { }
-
-    static bool ensureInit_l();
-
-    static status_t registerFactory_l(IFactory* factory,
-                                      player2_type type);
-
-    static Mutex       sLock;
-    static tFactoryMap *sFactoryMap;
-    static bool        sInitComplete;
-
-    DISALLOW_EVIL_CONSTRUCTORS(MediaPlayer2Factory);
-};
-
-}  // namespace android
-#endif  // ANDROID_MEDIAPLAYER2FACTORY_H
diff --git a/media/libmedia/MediaPlayer2Manager.cpp b/media/libmedia/MediaPlayer2Manager.cpp
index c119750..aefb91c 100644
--- a/media/libmedia/MediaPlayer2Manager.cpp
+++ b/media/libmedia/MediaPlayer2Manager.cpp
@@ -68,8 +68,8 @@
 
 #include <private/android_filesystem_config.h>
 
+#include <nuplayer2/NuPlayer2Driver.h>
 #include "MediaPlayer2Manager.h"
-#include "MediaPlayer2Factory.h"
 
 static const int kDumpLockRetries = 50;
 static const int kDumpLockSleepUs = 20000;
@@ -269,8 +269,6 @@
     mPid = IPCThreadState::self()->getCallingPid();
     mUid = IPCThreadState::self()->getCallingUid();
     mNextConnId = 1;
-
-    MediaPlayer2Factory::registerBuiltinFactories();
 }
 
 MediaPlayer2Manager::~MediaPlayer2Manager() {
@@ -330,7 +328,7 @@
             mPid, mConnId, mStatus, mLoop?"true": "false");
     result.append(buffer);
 
-    sp<MediaPlayer2Base> p;
+    sp<MediaPlayer2Interface> p;
     sp<AudioOutput> audioOutput;
     bool locked = false;
     for (int i = 0; i < kDumpLockRetries; ++i) {
@@ -534,7 +532,7 @@
     ALOGV("disconnect(%d) from pid %d", mConnId, mPid);
     // grab local reference and clear main reference to prevent future
     // access to object
-    sp<MediaPlayer2Base> p;
+    sp<MediaPlayer2Interface> p;
     {
         Mutex::Autolock l(mLock);
         p = mPlayer;
@@ -562,16 +560,17 @@
     IPCThreadState::self()->flushCommands();
 }
 
-sp<MediaPlayer2Base> MediaPlayer2Manager::Client::createPlayer(player2_type playerType)
-{
-    // determine if we have the right player type
-    sp<MediaPlayer2Base> p = getPlayer();
-    if ((p != NULL) && (p->playerType() != playerType)) {
-        ALOGV("delete player");
-        p.clear();
-    }
+sp<MediaPlayer2Interface> MediaPlayer2Manager::Client::createPlayer() {
+    sp<MediaPlayer2Interface> p = getPlayer();
     if (p == NULL) {
-        p = MediaPlayer2Factory::createPlayer(playerType, this, notify, mPid);
+        p = new NuPlayer2Driver(mPid);
+        status_t init_result = p->initCheck();
+        if (init_result == NO_ERROR) {
+            p->setNotifyCallback(this, notify);
+        } else {
+            ALOGE("Failed to create player, initCheck failed(res = %d)", init_result);
+            p.clear();
+        }
     }
 
     if (p != NULL) {
@@ -584,7 +583,7 @@
 void MediaPlayer2Manager::Client::AudioDeviceUpdatedNotifier::onAudioDeviceUpdate(
         audio_io_handle_t audioIo,
         audio_port_handle_t deviceId) {
-    sp<MediaPlayer2Base> listener = mListener.promote();
+    sp<MediaPlayer2Interface> listener = mListener.promote();
     if (listener != NULL) {
         listener->sendEvent(MEDIA2_AUDIO_ROUTING_CHANGED, audioIo, deviceId);
     } else {
@@ -592,13 +591,8 @@
     }
 }
 
-sp<MediaPlayer2Base> MediaPlayer2Manager::Client::setDataSource_pre(
-        player2_type playerType)
-{
-    ALOGV("player type = %d", playerType);
-
-    // create the right type of player
-    sp<MediaPlayer2Base> p = createPlayer(playerType);
+sp<MediaPlayer2Interface> MediaPlayer2Manager::Client::setDataSource_pre() {
+    sp<MediaPlayer2Interface> p = createPlayer();
     if (p == NULL) {
         return p;
     }
@@ -607,17 +601,15 @@
 
     mAudioDeviceUpdatedListener = new AudioDeviceUpdatedNotifier(p);
 
-    if (!p->hardwareOutput()) {
-        mAudioOutput = new AudioOutput(mAudioSessionId, mUid,
-                mPid, mAudioAttributes, mAudioDeviceUpdatedListener);
-        static_cast<MediaPlayer2Interface*>(p.get())->setAudioSink(mAudioOutput);
-    }
+    mAudioOutput = new AudioOutput(mAudioSessionId, mUid,
+            mPid, mAudioAttributes, mAudioDeviceUpdatedListener);
+    p->setAudioSink(mAudioOutput);
 
     return p;
 }
 
 status_t MediaPlayer2Manager::Client::setDataSource_post(
-        const sp<MediaPlayer2Base>& p,
+        const sp<MediaPlayer2Interface>& p,
         status_t status)
 {
     ALOGV(" setDataSource");
@@ -663,8 +655,7 @@
         mStatus = UNKNOWN_ERROR;
         return mStatus;
     } else {
-        player2_type playerType = MediaPlayer2Factory::getPlayerType(this, url);
-        sp<MediaPlayer2Base> p = setDataSource_pre(playerType);
+        sp<MediaPlayer2Interface> p = setDataSource_pre();
         if (p == NULL) {
             return NO_INIT;
         }
@@ -701,11 +692,7 @@
         ALOGV("calculated length = %lld", (long long)length);
     }
 
-    player2_type playerType = MediaPlayer2Factory::getPlayerType(this,
-                                                               fd,
-                                                               offset,
-                                                               length);
-    sp<MediaPlayer2Base> p = setDataSource_pre(playerType);
+    sp<MediaPlayer2Interface> p = setDataSource_pre();
     if (p == NULL) {
         return NO_INIT;
     }
@@ -716,9 +703,7 @@
 
 status_t MediaPlayer2Manager::Client::setDataSource(
         const sp<IStreamSource> &source) {
-    // create the right type of player
-    player2_type playerType = MediaPlayer2Factory::getPlayerType(this, source);
-    sp<MediaPlayer2Base> p = setDataSource_pre(playerType);
+    sp<MediaPlayer2Interface> p = setDataSource_pre();
     if (p == NULL) {
         return NO_INIT;
     }
@@ -729,8 +714,7 @@
 
 status_t MediaPlayer2Manager::Client::setDataSource(
         const sp<DataSource> &source) {
-    player2_type playerType = MediaPlayer2Factory::getPlayerType(this, source);
-    sp<MediaPlayer2Base> p = setDataSource_pre(playerType);
+    sp<MediaPlayer2Interface> p = setDataSource_pre();
     if (p == NULL) {
         return NO_INIT;
     }
@@ -757,7 +741,7 @@
     ALOGV("[%d] setVideoSurfaceTexture(%p)",
           mConnId,
           (nww == NULL ? NULL : nww->getANativeWindow()));
-    sp<MediaPlayer2Base> p = getPlayer();
+    sp<MediaPlayer2Interface> p = getPlayer();
     if (p == 0) return UNKNOWN_ERROR;
 
     if (nww != NULL && nww->getANativeWindow() != NULL) {
@@ -810,7 +794,7 @@
 status_t MediaPlayer2Manager::Client::invoke(const Parcel& request,
                                             Parcel *reply)
 {
-    sp<MediaPlayer2Base> p = getPlayer();
+    sp<MediaPlayer2Interface> p = getPlayer();
     if (p == NULL) return UNKNOWN_ERROR;
     return p->invoke(request, reply);
 }
@@ -834,7 +818,7 @@
 status_t MediaPlayer2Manager::Client::getMetadata(
         bool update_only, bool /*apply_filter*/, Parcel *reply)
 {
-    sp<MediaPlayer2Base> player = getPlayer();
+    sp<MediaPlayer2Interface> player = getPlayer();
     if (player == 0) return UNKNOWN_ERROR;
 
     status_t status;
@@ -879,7 +863,7 @@
 {
     ALOGV("[%d] setBufferingSettings{%s}",
             mConnId, buffering.toString().string());
-    sp<MediaPlayer2Base> p = getPlayer();
+    sp<MediaPlayer2Interface> p = getPlayer();
     if (p == 0) return UNKNOWN_ERROR;
     return p->setBufferingSettings(buffering);
 }
@@ -887,7 +871,7 @@
 status_t MediaPlayer2Manager::Client::getBufferingSettings(
         BufferingSettings* buffering /* nonnull */)
 {
-    sp<MediaPlayer2Base> p = getPlayer();
+    sp<MediaPlayer2Interface> p = getPlayer();
     // TODO: create mPlayer on demand.
     if (p == 0) return UNKNOWN_ERROR;
     status_t ret = p->getBufferingSettings(buffering);
@@ -903,7 +887,7 @@
 status_t MediaPlayer2Manager::Client::prepareAsync()
 {
     ALOGV("[%d] prepareAsync", mConnId);
-    sp<MediaPlayer2Base> p = getPlayer();
+    sp<MediaPlayer2Interface> p = getPlayer();
     if (p == 0) return UNKNOWN_ERROR;
     status_t ret = p->prepareAsync();
 #if CALLBACK_ANTAGONIZER
@@ -916,7 +900,7 @@
 status_t MediaPlayer2Manager::Client::start()
 {
     ALOGV("[%d] start", mConnId);
-    sp<MediaPlayer2Base> p = getPlayer();
+    sp<MediaPlayer2Interface> p = getPlayer();
     if (p == 0) return UNKNOWN_ERROR;
     p->setLooping(mLoop);
     return p->start();
@@ -925,7 +909,7 @@
 status_t MediaPlayer2Manager::Client::stop()
 {
     ALOGV("[%d] stop", mConnId);
-    sp<MediaPlayer2Base> p = getPlayer();
+    sp<MediaPlayer2Interface> p = getPlayer();
     if (p == 0) return UNKNOWN_ERROR;
     return p->stop();
 }
@@ -933,7 +917,7 @@
 status_t MediaPlayer2Manager::Client::pause()
 {
     ALOGV("[%d] pause", mConnId);
-    sp<MediaPlayer2Base> p = getPlayer();
+    sp<MediaPlayer2Interface> p = getPlayer();
     if (p == 0) return UNKNOWN_ERROR;
     return p->pause();
 }
@@ -941,7 +925,7 @@
 status_t MediaPlayer2Manager::Client::isPlaying(bool* state)
 {
     *state = false;
-    sp<MediaPlayer2Base> p = getPlayer();
+    sp<MediaPlayer2Interface> p = getPlayer();
     if (p == 0) return UNKNOWN_ERROR;
     *state = p->isPlaying();
     ALOGV("[%d] isPlaying: %d", mConnId, *state);
@@ -952,14 +936,14 @@
 {
     ALOGV("[%d] setPlaybackSettings(%f, %f, %d, %d)",
             mConnId, rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode);
-    sp<MediaPlayer2Base> p = getPlayer();
+    sp<MediaPlayer2Interface> p = getPlayer();
     if (p == 0) return UNKNOWN_ERROR;
     return p->setPlaybackSettings(rate);
 }
 
 status_t MediaPlayer2Manager::Client::getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */)
 {
-    sp<MediaPlayer2Base> p = getPlayer();
+    sp<MediaPlayer2Interface> p = getPlayer();
     if (p == 0) return UNKNOWN_ERROR;
     status_t ret = p->getPlaybackSettings(rate);
     if (ret == NO_ERROR) {
@@ -976,7 +960,7 @@
 {
     ALOGV("[%d] setSyncSettings(%u, %u, %f, %f)",
             mConnId, sync.mSource, sync.mAudioAdjustMode, sync.mTolerance, videoFpsHint);
-    sp<MediaPlayer2Base> p = getPlayer();
+    sp<MediaPlayer2Interface> p = getPlayer();
     if (p == 0) return UNKNOWN_ERROR;
     return p->setSyncSettings(sync, videoFpsHint);
 }
@@ -984,7 +968,7 @@
 status_t MediaPlayer2Manager::Client::getSyncSettings(
         AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */)
 {
-    sp<MediaPlayer2Base> p = getPlayer();
+    sp<MediaPlayer2Interface> p = getPlayer();
     if (p == 0) return UNKNOWN_ERROR;
     status_t ret = p->getSyncSettings(sync, videoFps);
     if (ret == NO_ERROR) {
@@ -999,7 +983,7 @@
 status_t MediaPlayer2Manager::Client::getCurrentPosition(int *msec)
 {
     ALOGV("getCurrentPosition");
-    sp<MediaPlayer2Base> p = getPlayer();
+    sp<MediaPlayer2Interface> p = getPlayer();
     if (p == 0) return UNKNOWN_ERROR;
     status_t ret = p->getCurrentPosition(msec);
     if (ret == NO_ERROR) {
@@ -1013,7 +997,7 @@
 status_t MediaPlayer2Manager::Client::getDuration(int *msec)
 {
     ALOGV("getDuration");
-    sp<MediaPlayer2Base> p = getPlayer();
+    sp<MediaPlayer2Interface> p = getPlayer();
     if (p == 0) return UNKNOWN_ERROR;
     status_t ret = p->getDuration(msec);
     if (ret == NO_ERROR) {
@@ -1037,7 +1021,7 @@
     if (c != NULL) {
         if (mAudioOutput != NULL) {
             mAudioOutput->setNextOutput(c->mAudioOutput);
-        } else if ((mPlayer != NULL) && !mPlayer->hardwareOutput()) {
+        } else {
             ALOGE("no current audio output");
         }
 
@@ -1054,13 +1038,9 @@
         const sp<VolumeShaper::Operation>& operation) {
     // for hardware output, call player instead
     ALOGV("Client::applyVolumeShaper(%p)", this);
-    sp<MediaPlayer2Base> p = getPlayer();
+    sp<MediaPlayer2Interface> p = getPlayer();
     {
         Mutex::Autolock l(mLock);
-        if (p != 0 && p->hardwareOutput()) {
-            // TODO: investigate internal implementation
-            return VolumeShaper::Status(INVALID_OPERATION);
-        }
         if (mAudioOutput.get() != nullptr) {
             return mAudioOutput->applyVolumeShaper(configuration, operation);
         }
@@ -1071,13 +1051,9 @@
 sp<VolumeShaper::State> MediaPlayer2Manager::Client::getVolumeShaperState(int id) {
     // for hardware output, call player instead
     ALOGV("Client::getVolumeShaperState(%p)", this);
-    sp<MediaPlayer2Base> p = getPlayer();
+    sp<MediaPlayer2Interface> p = getPlayer();
     {
         Mutex::Autolock l(mLock);
-        if (p != 0 && p->hardwareOutput()) {
-            // TODO: investigate internal implementation.
-            return nullptr;
-        }
         if (mAudioOutput.get() != nullptr) {
             return mAudioOutput->getVolumeShaperState(id);
         }
@@ -1088,7 +1064,7 @@
 status_t MediaPlayer2Manager::Client::seekTo(int msec, MediaPlayer2SeekMode mode)
 {
     ALOGV("[%d] seekTo(%d, %d)", mConnId, msec, mode);
-    sp<MediaPlayer2Base> p = getPlayer();
+    sp<MediaPlayer2Interface> p = getPlayer();
     if (p == 0) return UNKNOWN_ERROR;
     return p->seekTo(msec, mode);
 }
@@ -1097,7 +1073,7 @@
 {
     ALOGV("[%d] reset", mConnId);
     mRetransmitEndpointValid = false;
-    sp<MediaPlayer2Base> p = getPlayer();
+    sp<MediaPlayer2Interface> p = getPlayer();
     if (p == 0) return UNKNOWN_ERROR;
     return p->reset();
 }
@@ -1105,7 +1081,7 @@
 status_t MediaPlayer2Manager::Client::notifyAt(int64_t mediaTimeUs)
 {
     ALOGV("[%d] notifyAt(%lld)", mConnId, (long long)mediaTimeUs);
-    sp<MediaPlayer2Base> p = getPlayer();
+    sp<MediaPlayer2Interface> p = getPlayer();
     if (p == 0) return UNKNOWN_ERROR;
     return p->notifyAt(mediaTimeUs);
 }
@@ -1142,7 +1118,7 @@
 {
     ALOGV("[%d] setLooping(%d)", mConnId, loop);
     mLoop = loop;
-    sp<MediaPlayer2Base> p = getPlayer();
+    sp<MediaPlayer2Interface> p = getPlayer();
     if (p != 0) return p->setLooping(loop);
     return NO_ERROR;
 }
@@ -1152,17 +1128,10 @@
     ALOGV("[%d] setVolume(%f, %f)", mConnId, leftVolume, rightVolume);
 
     // for hardware output, call player instead
-    sp<MediaPlayer2Base> p = getPlayer();
+    sp<MediaPlayer2Interface> p = getPlayer();
     {
       Mutex::Autolock l(mLock);
-      if (p != 0 && p->hardwareOutput()) {
-          MediaPlayerHWInterface* hwp =
-                  reinterpret_cast<MediaPlayerHWInterface*>(p.get());
-          return hwp->setVolume(leftVolume, rightVolume);
-      } else {
-          if (mAudioOutput != 0) mAudioOutput->setVolume(leftVolume, rightVolume);
-          return NO_ERROR;
-      }
+      if (mAudioOutput != 0) mAudioOutput->setVolume(leftVolume, rightVolume);
     }
 
     return NO_ERROR;
@@ -1193,7 +1162,7 @@
         return setAudioAttributes_l(request);
     }
     default:
-        sp<MediaPlayer2Base> p = getPlayer();
+        sp<MediaPlayer2Interface> p = getPlayer();
         if (p == 0) { return UNKNOWN_ERROR; }
         return p->setParameter(key, request);
     }
@@ -1201,7 +1170,7 @@
 
 status_t MediaPlayer2Manager::Client::getParameter(int key, Parcel *reply) {
     ALOGV("[%d] getParameter(%d)", mConnId, key);
-    sp<MediaPlayer2Base> p = getPlayer();
+    sp<MediaPlayer2Interface> p = getPlayer();
     if (p == 0) return UNKNOWN_ERROR;
     return p->getParameter(key, reply);
 }
@@ -1218,7 +1187,7 @@
         ALOGV("[%d] setRetransmitEndpoint = <none>", mConnId);
     }
 
-    sp<MediaPlayer2Base> p = getPlayer();
+    sp<MediaPlayer2Interface> p = getPlayer();
 
     // Right now, the only valid time to set a retransmit endpoint is before
     // player selection has been made (since the presence or absence of a
@@ -1244,7 +1213,7 @@
     if (NULL == endpoint)
         return BAD_VALUE;
 
-    sp<MediaPlayer2Base> p = getPlayer();
+    sp<MediaPlayer2Interface> p = getPlayer();
 
     if (p != NULL)
         return p->getRetransmitEndpoint(endpoint);
@@ -1347,7 +1316,7 @@
         const Vector<uint8_t>& drmSessionId)
 {
     ALOGV("[%d] prepareDrm", mConnId);
-    sp<MediaPlayer2Base> p = getPlayer();
+    sp<MediaPlayer2Interface> p = getPlayer();
     if (p == 0) return UNKNOWN_ERROR;
 
     status_t ret = p->prepareDrm(uuid, drmSessionId);
@@ -1359,7 +1328,7 @@
 status_t MediaPlayer2Manager::Client::releaseDrm()
 {
     ALOGV("[%d] releaseDrm", mConnId);
-    sp<MediaPlayer2Base> p = getPlayer();
+    sp<MediaPlayer2Interface> p = getPlayer();
     if (p == 0) return UNKNOWN_ERROR;
 
     status_t ret = p->releaseDrm();
diff --git a/media/libmedia/MediaPlayer2Manager.h b/media/libmedia/MediaPlayer2Manager.h
index b42cbbb..20cc735 100644
--- a/media/libmedia/MediaPlayer2Manager.h
+++ b/media/libmedia/MediaPlayer2Manager.h
@@ -48,7 +48,7 @@
 class Antagonizer {
 public:
     Antagonizer(
-            MediaPlayer2Base::NotifyCallback cb,
+            MediaPlayer2Interface::NotifyCallback cb,
             const wp<MediaPlayer2Engine> &client);
     void start() { mActive = true; }
     void stop() { mActive = false; }
@@ -62,14 +62,14 @@
     bool                             mExit;
     bool                             mActive;
     wp<MediaPlayer2Engine>           mClient;
-    MediaPlayer2Base::NotifyCallback mCb;
+    MediaPlayer2Interface::NotifyCallback mCb;
 };
 #endif
 
 class MediaPlayer2Manager {
     class Client;
 
-    class AudioOutput : public MediaPlayer2Base::AudioSink
+    class AudioOutput : public MediaPlayer2Interface::AudioSink
     {
         class CallbackData;
 
@@ -287,7 +287,7 @@
                                         const sp<media::VolumeShaper::Operation>& operation) override;
         virtual sp<media::VolumeShaper::State> getVolumeShaperState(int id) override;
 
-        sp<MediaPlayer2Base>    createPlayer(player2_type playerType);
+        sp<MediaPlayer2Interface>    createPlayer();
 
         virtual status_t        setDataSource(
                         const sp<MediaHTTPService> &httpService,
@@ -300,8 +300,8 @@
         virtual status_t        setDataSource(const sp<DataSource> &source);
 
 
-        sp<MediaPlayer2Base>    setDataSource_pre(player2_type playerType);
-        status_t                setDataSource_post(const sp<MediaPlayer2Base>& p,
+        sp<MediaPlayer2Interface>    setDataSource_pre();
+        status_t                setDataSource_post(const sp<MediaPlayer2Interface>& p,
                                                    status_t status);
 
         static  void            notify(const wp<MediaPlayer2Engine> &listener, int msg,
@@ -323,7 +323,7 @@
         class AudioDeviceUpdatedNotifier: public AudioSystem::AudioDeviceCallback
         {
         public:
-            AudioDeviceUpdatedNotifier(const sp<MediaPlayer2Base>& listener) {
+            AudioDeviceUpdatedNotifier(const sp<MediaPlayer2Interface>& listener) {
                 mListener = listener;
             }
             ~AudioDeviceUpdatedNotifier() {}
@@ -332,7 +332,7 @@
                                              audio_port_handle_t deviceId);
 
         private:
-            wp<MediaPlayer2Base> mListener;
+            wp<MediaPlayer2Interface> mListener;
         };
 
         friend class MediaPlayer2Manager;
@@ -346,7 +346,7 @@
 
                 void            deletePlayer();
 
-        sp<MediaPlayer2Base>     getPlayer() const { Mutex::Autolock lock(mLock); return mPlayer; }
+        sp<MediaPlayer2Interface> getPlayer() const { Mutex::Autolock lock(mLock); return mPlayer; }
 
 
 
@@ -366,7 +366,7 @@
         status_t setAudioAttributes_l(const Parcel &request);
 
         mutable     Mutex                        mLock;
-                    sp<MediaPlayer2Base>         mPlayer;
+                    sp<MediaPlayer2Interface>    mPlayer;
                     sp<MediaPlayer2EngineClient> mClient;
                     sp<AudioOutput>              mAudioOutput;
                     pid_t                        mPid;
diff --git a/media/libmedia/TestPlayerStub.cpp b/media/libmedia/TestPlayerStub.cpp
deleted file mode 100644
index 3548793..0000000
--- a/media/libmedia/TestPlayerStub.cpp
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "TestPlayerStub"
-#include "utils/Log.h"
-
-#include "TestPlayerStub.h"
-
-#include <dlfcn.h>  // for dlopen/dlclose
-#include <stdlib.h>
-#include <string.h>
-#include <cutils/properties.h>
-#include <utils/Errors.h>  // for status_t
-
-#include "media/MediaPlayer2Interface.h"
-
-
-namespace {
-using android::status_t;
-using android::MediaPlayer2Base;
-
-const char *kTestUrlScheme = "test:";
-const char *kUrlParam = "url=";
-
-const char *kBuildTypePropName = "ro.build.type";
-const char *kEngBuild = "eng";
-const char *kTestBuild = "test";
-
-// @return true if the current build is 'eng' or 'test'.
-bool isTestBuild()
-{
-    char prop[PROPERTY_VALUE_MAX] = { '\0', };
-
-    property_get(kBuildTypePropName, prop, "\0");
-    return strcmp(prop, kEngBuild) == 0 || strcmp(prop, kTestBuild) == 0;
-}
-
-// @return true if the url scheme is 'test:'
-bool isTestUrl(const char *url)
-{
-    return url && strncmp(url, kTestUrlScheme, strlen(kTestUrlScheme)) == 0;
-}
-
-}  // anonymous namespace
-
-namespace android {
-
-TestPlayerStub::TestPlayerStub()
-    :mUrl(NULL), mFilename(NULL), mContentUrl(NULL),
-     mHandle(NULL), mNewPlayer(NULL), mDeletePlayer(NULL),
-     mPlayer(NULL) { }
-
-TestPlayerStub::~TestPlayerStub()
-{
-    resetInternal();
-}
-
-status_t TestPlayerStub::initCheck()
-{
-    return isTestBuild() ? OK : INVALID_OPERATION;
-}
-
-// Parse mUrl to get:
-// * The library to be dlopened.
-// * The url to be passed to the real setDataSource impl.
-//
-// mUrl is expected to be in following format:
-//
-// test:<name of the .so>?url=<url for setDataSource>
-//
-// The value of the url parameter is treated as a string (no
-// unescaping of illegal charaters).
-status_t TestPlayerStub::parseUrl()
-{
-    if (strlen(mUrl) < strlen(kTestUrlScheme)) {
-        resetInternal();
-        return BAD_VALUE;
-    }
-
-    char *i = mUrl + strlen(kTestUrlScheme);
-
-    mFilename = i;
-
-    while (*i != '\0' && *i != '?') {
-        ++i;
-    }
-
-    if (*i == '\0' || strncmp(i + 1, kUrlParam, strlen(kUrlParam)) != 0) {
-        resetInternal();
-        return BAD_VALUE;
-    }
-    *i = '\0';  // replace '?' to nul-terminate mFilename
-
-    mContentUrl = i + 1 + strlen(kUrlParam);
-    return OK;
-}
-
-// Load the dynamic library.
-// Create the test player.
-// Call setDataSource on the test player with the url in param.
-status_t TestPlayerStub::setDataSource(
-        const sp<MediaHTTPService> &httpService,
-        const char *url,
-        const KeyedVector<String8, String8> *headers) {
-    if (!isTestUrl(url) || NULL != mHandle) {
-        return INVALID_OPERATION;
-    }
-
-    mUrl = strdup(url);
-
-    status_t status = parseUrl();
-
-    if (OK != status) {
-        resetInternal();
-        return status;
-    }
-
-    ::dlerror();  // Clears any pending error.
-
-    // Load the test player from the url. dlopen will fail if the lib
-    // is not there. dls are under /system/lib
-    // None of the entry points should be NULL.
-    mHandle = ::dlopen(mFilename, RTLD_NOW | RTLD_GLOBAL);
-    if (!mHandle) {
-        ALOGE("dlopen failed: %s", ::dlerror());
-        resetInternal();
-        return UNKNOWN_ERROR;
-    }
-
-    // Load the 2 entry points to create and delete instances.
-    const char *err;
-    mNewPlayer = reinterpret_cast<NEW_PLAYER>(dlsym(mHandle,
-                                                    "newPlayer"));
-    err = ::dlerror();
-    if (err || mNewPlayer == NULL) {
-        // if err is NULL the string <null> is inserted in the logs =>
-        // mNewPlayer was NULL.
-        ALOGE("dlsym for newPlayer failed %s", err);
-        resetInternal();
-        return UNKNOWN_ERROR;
-    }
-
-    mDeletePlayer = reinterpret_cast<DELETE_PLAYER>(dlsym(mHandle,
-                                                          "deletePlayer"));
-    err = ::dlerror();
-    if (err || mDeletePlayer == NULL) {
-        ALOGE("dlsym for deletePlayer failed %s", err);
-        resetInternal();
-        return UNKNOWN_ERROR;
-    }
-
-    mPlayer = (*mNewPlayer)();
-    return mPlayer->setDataSource(httpService, mContentUrl, headers);
-}
-
-// Internal cleanup.
-status_t TestPlayerStub::resetInternal()
-{
-    if(mUrl) {
-        free(mUrl);
-        mUrl = NULL;
-    }
-    mFilename = NULL;
-    mContentUrl = NULL;
-
-    if (mPlayer) {
-        ALOG_ASSERT(mDeletePlayer != NULL, "mDeletePlayer is null");
-        (*mDeletePlayer)(mPlayer);
-        mPlayer = NULL;
-    }
-
-    if (mHandle) {
-        ::dlclose(mHandle);
-        mHandle = NULL;
-    }
-    return OK;
-}
-
-/* static */ bool TestPlayerStub::canBeUsed(const char *url)
-{
-    return isTestBuild() && isTestUrl(url);
-}
-
-}  // namespace android
diff --git a/media/libmedia/TestPlayerStub.h b/media/libmedia/TestPlayerStub.h
deleted file mode 100644
index 27c8bf4..0000000
--- a/media/libmedia/TestPlayerStub.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_FRAMEWORKS_BASE_MEDIA_LIBMEDIA_TESTPLAYERSTUB_H__
-#define ANDROID_FRAMEWORKS_BASE_MEDIA_LIBMEDIA_TESTPLAYERSTUB_H__
-
-#include <media/MediaPlayer2Interface.h>
-#include <utils/Errors.h>
-
-namespace android {
-class MediaPlayer2Base;  // in media/MediaPlayer2Interface.h
-
-// Wrapper around a test media player that gets dynamically loaded.
-//
-// The URL passed to setDataSource has this format:
-//
-//   test:<name of the .so>?url=<url for the real setDataSource impl.>
-//
-// e.g:
-//   test:invoke_test_media_player.so?url=http://youtube.com/
-//   test:invoke_test_media_player.so?url=speedtest
-//
-// TestPlayerStub::setDataSource loads the library in the test url. 2
-// entry points with C linkage are expected. One to create the test
-// player and one to destroy it.
-//
-// extern "C" android::MediaPlayer2Base* newPlayer();
-// extern "C" android::status_t deletePlayer(android::MediaPlayer2Base *p);
-//
-// Once the test player has been loaded, its setDataSource
-// implementation is called with the value of the 'url' parameter.
-//
-// typical usage in a java test:
-// ============================
-//
-//  MediaPlayer2 p = new MediaPlayer2();
-//  p.setDataSource("test:invoke_mock_media_player.so?url=http://youtube.com");
-//  p.prepare();
-//  ...
-//  p.release();
-
-class TestPlayerStub : public MediaPlayer2Interface {
-  public:
-    typedef MediaPlayer2Base* (*NEW_PLAYER)();
-    typedef status_t (*DELETE_PLAYER)(MediaPlayer2Base *);
-
-    TestPlayerStub();
-    virtual ~TestPlayerStub();
-
-    // Called right after the constructor. Check if the current build
-    // allows test players.
-    virtual status_t initCheck();
-
-    // @param url Should be a test url. See class comment.
-    virtual status_t setDataSource(
-            const sp<MediaHTTPService> &httpService,
-            const char* url,
-            const KeyedVector<String8, String8> *headers);
-
-    // Test player for a file descriptor source is not supported.
-    virtual status_t setDataSource(int, int64_t, int64_t)  {
-        return INVALID_OPERATION;
-    }
-
-
-    // All the methods below wrap the mPlayer instance.
-    virtual status_t setVideoSurfaceTexture(
-            const android::sp<android::ANativeWindowWrapper>& st)  {
-        return mPlayer->setVideoSurfaceTexture(st);
-    }
-    virtual status_t prepare() {return mPlayer->prepare();}
-    virtual status_t prepareAsync()  {return mPlayer->prepareAsync();}
-    virtual status_t start()  {return mPlayer->start();}
-    virtual status_t stop()  {return mPlayer->stop();}
-    virtual status_t pause()  {return mPlayer->pause();}
-    virtual bool isPlaying() {return mPlayer->isPlaying();}
-    virtual status_t seekTo(
-            int msec,
-            MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC) {
-        return mPlayer->seekTo(msec, mode);
-    }
-    virtual status_t getCurrentPosition(int *p)  {
-        return mPlayer->getCurrentPosition(p);
-    }
-    virtual status_t getDuration(int *d)  {return mPlayer->getDuration(d);}
-    virtual status_t reset() {return mPlayer->reset();}
-    virtual status_t setLooping(int b)  {return mPlayer->setLooping(b);}
-    virtual player2_type playerType() {return mPlayer->playerType();}
-    virtual status_t invoke(const android::Parcel& in, android::Parcel *out) {
-        return mPlayer->invoke(in, out);
-    }
-    virtual status_t setParameter(int key, const Parcel &request) {
-        return mPlayer->setParameter(key, request);
-    }
-    virtual status_t getParameter(int key, Parcel *reply) {
-        return mPlayer->getParameter(key, reply);
-    }
-
-
-    // @return true if the current build is 'eng' or 'test' and the
-    //              url's scheme is 'test:'
-    static bool canBeUsed(const char *url);
-
-  private:
-    // Release the player, dlclose the library.
-    status_t resetInternal();
-    status_t parseUrl();
-
-    char *mUrl;                // test:foo.so?url=http://bar
-    char *mFilename;           // foo.so
-    char *mContentUrl;         // http://bar
-    void *mHandle;             // returned by dlopen
-    NEW_PLAYER    mNewPlayer;
-    DELETE_PLAYER mDeletePlayer;
-    MediaPlayer2Base *mPlayer; // wrapped player
-};
-
-}  // namespace android
-
-#endif  // ANDROID_FRAMEWORKS_BASE_MEDIA_LIBMEDIA_TESTPLAYERSTUB_H__
diff --git a/media/libmedia/include/media/IMediaRecorder.h b/media/libmedia/include/media/IMediaRecorder.h
index 3cef329..379000e 100644
--- a/media/libmedia/include/media/IMediaRecorder.h
+++ b/media/libmedia/include/media/IMediaRecorder.h
@@ -19,7 +19,9 @@
 #define ANDROID_IMEDIARECORDER_H
 
 #include <binder/IInterface.h>
+#include <media/MicrophoneInfo.h>
 #include <system/audio.h>
+#include <vector>
 
 namespace android {
 
@@ -69,6 +71,9 @@
     virtual status_t setInputDevice(audio_port_handle_t deviceId) = 0;
     virtual status_t getRoutedDeviceId(audio_port_handle_t *deviceId) = 0;
     virtual status_t enableAudioDeviceCallback(bool enabled) = 0;
+    virtual status_t getActiveMicrophones(
+                        std::vector<media::MicrophoneInfo>* activeMicrophones) = 0;
+
 };
 
 // ----------------------------------------------------------------------------
diff --git a/media/libmedia/include/media/MediaPlayer2Interface.h b/media/libmedia/include/media/MediaPlayer2Interface.h
index 931a110..699618e 100644
--- a/media/libmedia/include/media/MediaPlayer2Interface.h
+++ b/media/libmedia/include/media/MediaPlayer2Interface.h
@@ -47,16 +47,6 @@
 
 template<typename T> class SortedVector;
 
-enum player2_type {
-    PLAYER2_STAGEFRIGHT_PLAYER = 3,
-    PLAYER2_NU_PLAYER2 = 4,
-    // Test players are available only in the 'test' and 'eng' builds.
-    // The shared library with the test player is passed passed as an
-    // argument to the 'test:' url in the setDataSource call.
-    PLAYER2_TEST_PLAYER = 5,
-};
-
-
 #define DEFAULT_AUDIOSINK_BUFFERCOUNT 4
 #define DEFAULT_AUDIOSINK_BUFFERSIZE 1200
 #define DEFAULT_AUDIOSINK_SAMPLERATE 44100
@@ -68,7 +58,7 @@
 #define AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US 5000000
 
 // abstract base class - use MediaPlayer2Interface
-class MediaPlayer2Base : public AHandler
+class MediaPlayer2Interface : public AHandler
 {
 public:
     // callback mechanism for passing messages to MediaPlayer2 object
@@ -158,15 +148,16 @@
         virtual status_t    enableAudioDeviceCallback(bool enabled);
     };
 
-                        MediaPlayer2Base() : mClient(0), mNotify(0) {}
-    virtual             ~MediaPlayer2Base() {}
+                        MediaPlayer2Interface() : mClient(0), mNotify(0) { }
+    virtual             ~MediaPlayer2Interface() { }
     virtual status_t    initCheck() = 0;
-    virtual bool        hardwareOutput() = 0;
 
     virtual status_t    setUID(uid_t /* uid */) {
         return INVALID_OPERATION;
     }
 
+    virtual void        setAudioSink(const sp<AudioSink>& audioSink) { mAudioSink = audioSink; }
+
     virtual status_t    setDataSource(
             const sp<MediaHTTPService> &httpService,
             const char *url,
@@ -234,7 +225,6 @@
         return INVALID_OPERATION;
     }
     virtual status_t    setLooping(int loop) = 0;
-    virtual player2_type playerType() = 0;
     virtual status_t    setParameter(int key, const Parcel &request) = 0;
     virtual status_t    getParameter(int key, Parcel *reply) = 0;
 
@@ -245,7 +235,7 @@
     virtual status_t getRetransmitEndpoint(struct sockaddr_in* /* endpoint */) {
         return INVALID_OPERATION;
     }
-    virtual status_t setNextPlayer(const sp<MediaPlayer2Base>& /* next */) {
+    virtual status_t setNextPlayer(const sp<MediaPlayer2Interface>& /* next */) {
         return OK;
     }
 
@@ -303,6 +293,9 @@
         return INVALID_OPERATION;
     }
 
+protected:
+    sp<AudioSink>       mAudioSink;
+
 private:
     friend class MediaPlayer2Manager;
 
@@ -311,27 +304,6 @@
     NotifyCallback         mNotify;
 };
 
-// Implement this class for media players that use the AudioFlinger software mixer
-class MediaPlayer2Interface : public MediaPlayer2Base
-{
-public:
-    virtual             ~MediaPlayer2Interface() { }
-    virtual bool        hardwareOutput() { return false; }
-    virtual void        setAudioSink(const sp<AudioSink>& audioSink) { mAudioSink = audioSink; }
-protected:
-    sp<AudioSink>       mAudioSink;
-};
-
-// Implement this class for media players that output audio directly to hardware
-class MediaPlayer2HWInterface : public MediaPlayer2Base
-{
-public:
-    virtual             ~MediaPlayer2HWInterface() {}
-    virtual bool        hardwareOutput() { return true; }
-    virtual status_t    setVolume(float leftVolume, float rightVolume) = 0;
-    virtual status_t    setAudioStreamType(audio_stream_type_t streamType) = 0;
-};
-
 }; // namespace android
 
 #endif // __cplusplus
diff --git a/media/libmedia/include/media/MediaRecorderBase.h b/media/libmedia/include/media/MediaRecorderBase.h
index 748153c..5340dde 100644
--- a/media/libmedia/include/media/MediaRecorderBase.h
+++ b/media/libmedia/include/media/MediaRecorderBase.h
@@ -19,10 +19,13 @@
 #define MEDIA_RECORDER_BASE_H_
 
 #include <media/AudioSystem.h>
+#include <media/MicrophoneInfo.h>
 #include <media/mediarecorder.h>
 
 #include <system/audio.h>
 
+#include <vector>
+
 namespace android {
 
 class ICameraRecordingProxy;
@@ -67,6 +70,9 @@
     virtual status_t getRoutedDeviceId(audio_port_handle_t* deviceId) = 0;
     virtual void setAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback) = 0;
     virtual status_t enableAudioDeviceCallback(bool enabled) = 0;
+    virtual status_t getActiveMicrophones(
+                        std::vector<media::MicrophoneInfo>* activeMicrophones) = 0;
+
 
 
 protected:
diff --git a/media/libmedia/include/media/mediarecorder.h b/media/libmedia/include/media/mediarecorder.h
index 5f2a6fe..d8b0fe7 100644
--- a/media/libmedia/include/media/mediarecorder.h
+++ b/media/libmedia/include/media/mediarecorder.h
@@ -24,6 +24,7 @@
 #include <utils/Errors.h>
 #include <media/IMediaRecorderClient.h>
 #include <media/IMediaDeathNotifier.h>
+#include <media/MicrophoneInfo.h>
 
 namespace android {
 
@@ -258,6 +259,7 @@
     status_t    setInputDevice(audio_port_handle_t deviceId);
     status_t    getRoutedDeviceId(audio_port_handle_t *deviceId);
     status_t    enableAudioDeviceCallback(bool enabled);
+    status_t    getActiveMicrophones(std::vector<media::MicrophoneInfo>* activeMicrophones);
 
 private:
     void                    doCleanUp();
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index aab845b..721a043 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -829,4 +829,15 @@
     return mMediaRecorder->enableAudioDeviceCallback(enabled);
 }
 
+status_t MediaRecorder::getActiveMicrophones(std::vector<media::MicrophoneInfo>* activeMicrophones)
+{
+    ALOGV("getActiveMicrophones");
+
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    return mMediaRecorder->getActiveMicrophones(activeMicrophones);
+}
+
 } // namespace android
diff --git a/media/libmedia/nuplayer2/GenericSource.cpp b/media/libmedia/nuplayer2/GenericSource.cpp
index 094af7e..6907216 100644
--- a/media/libmedia/nuplayer2/GenericSource.cpp
+++ b/media/libmedia/nuplayer2/GenericSource.cpp
@@ -1647,19 +1647,15 @@
         return OK; // source without DRM info
     }
 
-    Parcel parcel;
-    NuPlayer2Drm::retrieveDrmInfo(pssh, psshsize, &parcel);
-    ALOGV("checkDrmInfo: MEDIA2_DRM_INFO PSSH size: %d  Parcel size: %d  objects#: %d",
-          (int)psshsize, (int)parcel.dataSize(), (int)parcel.objectsCount());
+    sp<ABuffer> drmInfoBuffer = NuPlayer2Drm::retrieveDrmInfo(pssh, psshsize);
+    ALOGV("checkDrmInfo: MEDIA2_DRM_INFO PSSH size: %d drmInfoBuffer size: %d",
+          (int)psshsize, (int)drmInfoBuffer->size());
 
-    if (parcel.dataSize() == 0) {
-        ALOGE("checkDrmInfo: Unexpected parcel size: 0");
+    if (drmInfoBuffer->size() == 0) {
+        ALOGE("checkDrmInfo: Unexpected drmInfoBuffer size: 0");
         return UNKNOWN_ERROR;
     }
 
-    // Can't pass parcel as a message to the player. Converting Parcel->ABuffer to pass it
-    // to the Player's onSourceNotify then back to Parcel for calling driver's notifyListener.
-    sp<ABuffer> drmInfoBuffer = ABuffer::CreateAsCopy(parcel.data(), parcel.dataSize());
     notifyDrmInfo(drmInfoBuffer);
 
     return OK;
diff --git a/media/libmedia/nuplayer2/NuPlayer2.cpp b/media/libmedia/nuplayer2/NuPlayer2.cpp
index 2745219..2c7f416 100644
--- a/media/libmedia/nuplayer2/NuPlayer2.cpp
+++ b/media/libmedia/nuplayer2/NuPlayer2.cpp
@@ -64,7 +64,7 @@
 
 namespace android {
 
-static status_t sendMetaDataToHal(sp<MediaPlayer2Base::AudioSink>& sink,
+static status_t sendMetaDataToHal(sp<MediaPlayer2Interface::AudioSink>& sink,
                                   const sp<MetaData>& meta) {
     int32_t sampleRate = 0;
     int32_t bitRate = 0;
@@ -417,7 +417,7 @@
     msg->post();
 }
 
-void NuPlayer2::setAudioSink(const sp<MediaPlayer2Base::AudioSink> &sink) {
+void NuPlayer2::setAudioSink(const sp<MediaPlayer2Interface::AudioSink> &sink) {
     sp<AMessage> msg = new AMessage(kWhatSetAudioSink, this);
     msg->setObject("sink", sink);
     msg->post();
@@ -850,7 +850,7 @@
             sp<RefBase> obj;
             CHECK(msg->findObject("sink", &obj));
 
-            mAudioSink = static_cast<MediaPlayer2Base::AudioSink *>(obj.get());
+            mAudioSink = static_cast<MediaPlayer2Interface::AudioSink *>(obj.get());
             break;
         }
 
diff --git a/media/libmedia/nuplayer2/NuPlayer2.h b/media/libmedia/nuplayer2/NuPlayer2.h
index 638b259..23c4fdf 100644
--- a/media/libmedia/nuplayer2/NuPlayer2.h
+++ b/media/libmedia/nuplayer2/NuPlayer2.h
@@ -61,7 +61,7 @@
 
     void setVideoSurfaceTextureAsync(const sp<ANativeWindowWrapper> &nww);
 
-    void setAudioSink(const sp<MediaPlayer2Base::AudioSink> &sink);
+    void setAudioSink(const sp<MediaPlayer2Interface::AudioSink> &sink);
     status_t setPlaybackSettings(const AudioPlaybackRate &rate);
     status_t getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */);
     status_t setSyncSettings(const AVSyncSettings &sync, float videoFpsHint);
@@ -168,7 +168,7 @@
     sp<Source> mSource;
     uint32_t mSourceFlags;
     sp<ANativeWindowWrapper> mNativeWindow;
-    sp<MediaPlayer2Base::AudioSink> mAudioSink;
+    sp<MediaPlayer2Interface::AudioSink> mAudioSink;
     sp<DecoderBase> mVideoDecoder;
     bool mOffloadAudio;
     sp<DecoderBase> mAudioDecoder;
diff --git a/media/libmedia/nuplayer2/NuPlayer2Driver.cpp b/media/libmedia/nuplayer2/NuPlayer2Driver.cpp
index ccfcc47..e48acea 100644
--- a/media/libmedia/nuplayer2/NuPlayer2Driver.cpp
+++ b/media/libmedia/nuplayer2/NuPlayer2Driver.cpp
@@ -129,7 +129,6 @@
 
     // set up an analytics record
     mAnalyticsItem = new MediaAnalyticsItem(kKeyPlayer);
-    mAnalyticsItem->generateSessionID();
 
     mNuPlayer2Looper->start(
             false, /* runOnCallingThread */
@@ -661,14 +660,12 @@
     // So the canonical "empty" record has 3 elements in it.
     if (mAnalyticsItem->count() > 3) {
 
-        mAnalyticsItem->setFinalized(true);
         mAnalyticsItem->selfrecord();
 
         // re-init in case we prepare() and start() again.
         delete mAnalyticsItem ;
         mAnalyticsItem = new MediaAnalyticsItem(kKeyPlayer);
         if (mAnalyticsItem) {
-            mAnalyticsItem->generateSessionID();
             mAnalyticsItem->setUid(mClientUid);
         }
     } else {
@@ -736,10 +733,6 @@
     return OK;
 }
 
-player2_type NuPlayer2Driver::playerType() {
-    return PLAYER2_NU_PLAYER2;
-}
-
 status_t NuPlayer2Driver::invoke(const Parcel &request, Parcel *reply) {
     if (reply == NULL) {
         ALOGE("reply is a NULL pointer");
diff --git a/media/libmedia/nuplayer2/NuPlayer2Driver.h b/media/libmedia/nuplayer2/NuPlayer2Driver.h
index d393f9d..7bbb367 100644
--- a/media/libmedia/nuplayer2/NuPlayer2Driver.h
+++ b/media/libmedia/nuplayer2/NuPlayer2Driver.h
@@ -66,7 +66,6 @@
     virtual status_t reset();
     virtual status_t notifyAt(int64_t mediaTimeUs) override;
     virtual status_t setLooping(int loop);
-    virtual player2_type playerType();
     virtual status_t invoke(const Parcel &request, Parcel *reply);
     virtual void setAudioSink(const sp<AudioSink> &audioSink);
     virtual status_t setParameter(int key, const Parcel &request);
diff --git a/media/libmedia/nuplayer2/NuPlayer2Drm.cpp b/media/libmedia/nuplayer2/NuPlayer2Drm.cpp
index 4751849..4853ae1 100644
--- a/media/libmedia/nuplayer2/NuPlayer2Drm.cpp
+++ b/media/libmedia/nuplayer2/NuPlayer2Drm.cpp
@@ -21,7 +21,7 @@
 
 #include <media/NdkWrapper.h>
 #include <utils/Log.h>
-
+#include <sstream>
 
 namespace android {
 
@@ -105,26 +105,70 @@
     return supportedDRMs;
 }
 
-// Parcel has only private copy constructor so passing it in rather than returning
-void NuPlayer2Drm::retrieveDrmInfo(const void *pssh, size_t psshsize, Parcel *parcel)
+sp<ABuffer> NuPlayer2Drm::retrieveDrmInfo(const void *pssh, uint32_t psshsize)
 {
-    // 1) PSSH bytes
-    parcel->writeUint32(psshsize);
-    parcel->writeByteArray(psshsize, (const uint8_t*)pssh);
+    std::ostringstream buf;
 
-    ALOGV("retrieveDrmInfo: MEDIA2_DRM_INFO  PSSH: size: %zu %s", psshsize,
+    // 1) PSSH bytes
+    buf.write(reinterpret_cast<const char *>(&psshsize), sizeof(psshsize));
+    buf.write(reinterpret_cast<const char *>(pssh), psshsize);
+
+    ALOGV("retrieveDrmInfo: MEDIA2_DRM_INFO  PSSH: size: %u %s", psshsize,
             DrmUUID::arrayToHex((uint8_t*)pssh, psshsize).string());
 
     // 2) supportedDRMs
     Vector<DrmUUID> supportedDRMs = getSupportedDrmSchemes(pssh, psshsize);
-    parcel->writeUint32(supportedDRMs.size());
-    for (size_t i = 0; i < supportedDRMs.size(); i++) {
+    uint32_t n = supportedDRMs.size();
+    buf.write(reinterpret_cast<char *>(&n), sizeof(n));
+    for (size_t i = 0; i < n; i++) {
         DrmUUID uuid = supportedDRMs[i];
-        parcel->writeByteArray(DrmUUID::UUID_SIZE, uuid.ptr());
+        buf.write(reinterpret_cast<const char *>(&n), sizeof(n));
+        buf.write(reinterpret_cast<const char *>(uuid.ptr()), DrmUUID::UUID_SIZE);
 
         ALOGV("retrieveDrmInfo: MEDIA2_DRM_INFO  supportedScheme[%zu] %s", i,
                 uuid.toHexString().string());
     }
+
+    sp<ABuffer> drmInfoBuffer = ABuffer::CreateAsCopy(buf.str().c_str(), buf.tellp());
+    return drmInfoBuffer;
+}
+
+sp<ABuffer> NuPlayer2Drm::retrieveDrmInfo(PsshInfo *psshInfo)
+{
+
+    std::ostringstream pssh, drmInfo;
+
+    // 0) Generate PSSH bytes
+    for (size_t i = 0; i < psshInfo->numentries; i++) {
+        PsshEntry *entry = &psshInfo->entries[i];
+        uint32_t datalen = entry->datalen;
+        pssh.write(reinterpret_cast<const char *>(&entry->uuid), sizeof(entry->uuid));
+        pssh.write(reinterpret_cast<const char *>(&datalen), sizeof(datalen));
+        pssh.write(reinterpret_cast<const char *>(entry->data), datalen);
+    }
+
+    uint32_t psshSize = pssh.tellp();
+    const uint8_t* psshPtr = reinterpret_cast<const uint8_t*>(pssh.str().c_str());
+    const char *psshHex = DrmUUID::arrayToHex(psshPtr, psshSize).string();
+    ALOGV("retrieveDrmInfo: MEDIA_DRM_INFO  PSSH: size: %u %s", psshSize, psshHex);
+
+    // 1) Write PSSH bytes
+    drmInfo.write(reinterpret_cast<const char *>(&psshSize), sizeof(psshSize));
+    drmInfo.write(reinterpret_cast<const char *>(pssh.str().c_str()), psshSize);
+
+    // 2) Write supportedDRMs
+    uint32_t numentries = psshInfo->numentries;
+    drmInfo.write(reinterpret_cast<const char *>(&numentries), sizeof(numentries));
+    for (size_t i = 0; i < numentries; i++) {
+        PsshEntry *entry = &psshInfo->entries[i];
+        drmInfo.write(reinterpret_cast<const char *>(&entry->uuid), sizeof(entry->uuid));
+        ALOGV("retrieveDrmInfo: MEDIA_DRM_INFO  supportedScheme[%zu] %s", i,
+                DrmUUID::arrayToHex((const uint8_t*)&entry->uuid, sizeof(AMediaUUID)).string());
+    }
+
+    sp<ABuffer> drmInfoBuf = ABuffer::CreateAsCopy(drmInfo.str().c_str(), drmInfo.tellp());
+    drmInfoBuf->setRange(0, drmInfo.tellp());
+    return drmInfoBuf;
 }
 
 }   // namespace android
diff --git a/media/libmedia/nuplayer2/NuPlayer2Drm.h b/media/libmedia/nuplayer2/NuPlayer2Drm.h
index f9c8711..99d2415 100644
--- a/media/libmedia/nuplayer2/NuPlayer2Drm.h
+++ b/media/libmedia/nuplayer2/NuPlayer2Drm.h
@@ -17,8 +17,11 @@
 #ifndef NUPLAYER2_DRM_H_
 #define NUPLAYER2_DRM_H_
 
-#include <binder/Parcel.h>
+#include <media/NdkMediaExtractor.h>
+#include <media/stagefright/foundation/ABuffer.h>
 
+#include <utils/String8.h>
+#include <utils/Vector.h>
 
 namespace android {
 
@@ -76,8 +79,8 @@
         // static helpers - public
 
     public:
-        // Parcel has only private copy constructor so passing it in rather than returning
-        static void retrieveDrmInfo(const void *pssh, size_t psshsize, Parcel *parcel);
+        static sp<ABuffer> retrieveDrmInfo(const void *pssh, uint32_t psshsize);
+        static sp<ABuffer> retrieveDrmInfo(PsshInfo *);
 
     };  // NuPlayer2Drm
 
diff --git a/media/libmedia/nuplayer2/NuPlayer2Renderer.cpp b/media/libmedia/nuplayer2/NuPlayer2Renderer.cpp
index 1a9f246..a0bd900 100644
--- a/media/libmedia/nuplayer2/NuPlayer2Renderer.cpp
+++ b/media/libmedia/nuplayer2/NuPlayer2Renderer.cpp
@@ -87,7 +87,7 @@
 const int64_t NuPlayer2::Renderer::kMinPositionUpdateDelayUs = 100000ll;
 
 NuPlayer2::Renderer::Renderer(
-        const sp<MediaPlayer2Base::AudioSink> &sink,
+        const sp<MediaPlayer2Interface::AudioSink> &sink,
         const sp<MediaClock> &mediaClock,
         const sp<AMessage> &notify,
         uint32_t flags)
@@ -805,28 +805,28 @@
 
 // static
 size_t NuPlayer2::Renderer::AudioSinkCallback(
-        MediaPlayer2Base::AudioSink * /* audioSink */,
+        MediaPlayer2Interface::AudioSink * /* audioSink */,
         void *buffer,
         size_t size,
         void *cookie,
-        MediaPlayer2Base::AudioSink::cb_event_t event) {
+        MediaPlayer2Interface::AudioSink::cb_event_t event) {
     NuPlayer2::Renderer *me = (NuPlayer2::Renderer *)cookie;
 
     switch (event) {
-        case MediaPlayer2Base::AudioSink::CB_EVENT_FILL_BUFFER:
+        case MediaPlayer2Interface::AudioSink::CB_EVENT_FILL_BUFFER:
         {
             return me->fillAudioBuffer(buffer, size);
             break;
         }
 
-        case MediaPlayer2Base::AudioSink::CB_EVENT_STREAM_END:
+        case MediaPlayer2Interface::AudioSink::CB_EVENT_STREAM_END:
         {
             ALOGV("AudioSink::CB_EVENT_STREAM_END");
             me->notifyEOSCallback();
             break;
         }
 
-        case MediaPlayer2Base::AudioSink::CB_EVENT_TEAR_DOWN:
+        case MediaPlayer2Interface::AudioSink::CB_EVENT_TEAR_DOWN:
         {
             ALOGV("AudioSink::CB_EVENT_TEAR_DOWN");
             me->notifyAudioTearDown(kDueToError);
diff --git a/media/libmedia/nuplayer2/NuPlayer2Renderer.h b/media/libmedia/nuplayer2/NuPlayer2Renderer.h
index 3007654..62cf0d8 100644
--- a/media/libmedia/nuplayer2/NuPlayer2Renderer.h
+++ b/media/libmedia/nuplayer2/NuPlayer2Renderer.h
@@ -35,15 +35,15 @@
         FLAG_REAL_TIME = 1,
         FLAG_OFFLOAD_AUDIO = 2,
     };
-    Renderer(const sp<MediaPlayer2Base::AudioSink> &sink,
+    Renderer(const sp<MediaPlayer2Interface::AudioSink> &sink,
              const sp<MediaClock> &mediaClock,
              const sp<AMessage> &notify,
              uint32_t flags = 0);
 
     static size_t AudioSinkCallback(
-            MediaPlayer2Base::AudioSink *audioSink,
+            MediaPlayer2Interface::AudioSink *audioSink,
             void *data, size_t size, void *me,
-            MediaPlayer2Base::AudioSink::cb_event_t event);
+            MediaPlayer2Interface::AudioSink::cb_event_t event);
 
     void queueBuffer(
             bool audio,
@@ -148,7 +148,7 @@
 
     static const int64_t kMinPositionUpdateDelayUs;
 
-    sp<MediaPlayer2Base::AudioSink> mAudioSink;
+    sp<MediaPlayer2Interface::AudioSink> mAudioSink;
     bool mUseVirtualAudioSink;
     sp<AMessage> mNotify;
     Mutex mLock;
diff --git a/media/libmediaextractor/Android.bp b/media/libmediaextractor/Android.bp
index 984d4f1..4071fba 100644
--- a/media/libmediaextractor/Android.bp
+++ b/media/libmediaextractor/Android.bp
@@ -29,6 +29,7 @@
         "MediaSourceBase.cpp",
         "MediaSource.cpp",
         "MediaExtractor.cpp",
+        "MetaData.cpp",
     ],
 
     clang: true,
diff --git a/media/libstagefright/foundation/MetaData.cpp b/media/libmediaextractor/MetaData.cpp
similarity index 99%
rename from media/libstagefright/foundation/MetaData.cpp
rename to media/libmediaextractor/MetaData.cpp
index 2415c61..98cddbe 100644
--- a/media/libstagefright/foundation/MetaData.cpp
+++ b/media/libmediaextractor/MetaData.cpp
@@ -17,6 +17,7 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "MetaData"
 #include <inttypes.h>
+#include <binder/Parcel.h>
 #include <utils/KeyedVector.h>
 #include <utils/Log.h>
 
diff --git a/media/libmediaextractor/include/media/DataSource.h b/media/libmediaextractor/include/media/DataSource.h
index 9925a21..9f00e0a 100644
--- a/media/libmediaextractor/include/media/DataSource.h
+++ b/media/libmediaextractor/include/media/DataSource.h
@@ -59,20 +59,6 @@
     bool getUInt32Var(off64_t offset, uint32_t *x, size_t size);
     bool getUInt64Var(off64_t offset, uint64_t *x, size_t size);
 
-    // Reads in "count" entries of type T into vector *x.
-    // Returns true if "count" entries can be read.
-    // If fewer than "count" entries can be read, return false. In this case,
-    // the output vector *x will still have those entries that were read. Call
-    // x->size() to obtain the number of entries read.
-    // The optional parameter chunkSize specifies how many entries should be
-    // read from the data source at one time into a temporary buffer. Increasing
-    // chunkSize can improve the performance at the cost of extra memory usage.
-    // The default value for chunkSize is set to read at least 4k bytes at a
-    // time, depending on sizeof(T).
-    template <typename T>
-    bool getVector(off64_t offset, Vector<T>* x, size_t count,
-                   size_t chunkSize = (4095 / sizeof(T)) + 1);
-
     // May return ERROR_UNSUPPORTED.
     virtual status_t getSize(off64_t *size);
 
@@ -111,51 +97,6 @@
     DataSource &operator=(const DataSource &);
 };
 
-template <typename T>
-bool DataSource::getVector(off64_t offset, Vector<T>* x, size_t count,
-                           size_t chunkSize)
-{
-    x->clear();
-    if (chunkSize == 0) {
-        return false;
-    }
-    if (count == 0) {
-        return true;
-    }
-
-    T tmp[chunkSize];
-    ssize_t numBytesRead;
-    size_t numBytesPerChunk = chunkSize * sizeof(T);
-    size_t i;
-
-    for (i = 0; i + chunkSize < count; i += chunkSize) {
-        // This loops is executed when more than chunkSize records need to be
-        // read.
-        numBytesRead = this->readAt(offset, (void*)&tmp, numBytesPerChunk);
-        if (numBytesRead == -1) { // If readAt() returns -1, there is an error.
-            return false;
-        }
-        if (static_cast<size_t>(numBytesRead) < numBytesPerChunk) {
-            // This case is triggered when the stream ends before the whole
-            // chunk is read.
-            x->appendArray(tmp, (size_t)numBytesRead / sizeof(T));
-            return false;
-        }
-        x->appendArray(tmp, chunkSize);
-        offset += numBytesPerChunk;
-    }
-
-    // There are (count - i) more records to read.
-    // Right now, (count - i) <= chunkSize.
-    // We do the same thing as above, but with chunkSize replaced by count - i.
-    numBytesRead = this->readAt(offset, (void*)&tmp, (count - i) * sizeof(T));
-    if (numBytesRead == -1) {
-        return false;
-    }
-    x->appendArray(tmp, (size_t)numBytesRead / sizeof(T));
-    return x->size() == count;
-}
-
 }  // namespace android
 
 #endif  // DATA_SOURCE_H_
diff --git a/media/libmediaextractor/include/media/MediaExtractor.h b/media/libmediaextractor/include/media/MediaExtractor.h
index 15a5d8c..27581f3 100644
--- a/media/libmediaextractor/include/media/MediaExtractor.h
+++ b/media/libmediaextractor/include/media/MediaExtractor.h
@@ -22,6 +22,7 @@
 #include <vector>
 
 #include <utils/Errors.h>
+#include <utils/Log.h>
 #include <utils/RefBase.h>
 
 namespace android {
diff --git a/media/libmediaextractor/include/media/MediaSourceBase.h b/media/libmediaextractor/include/media/MediaSourceBase.h
index 77d4fc9..9db6099 100644
--- a/media/libmediaextractor/include/media/MediaSourceBase.h
+++ b/media/libmediaextractor/include/media/MediaSourceBase.h
@@ -24,6 +24,7 @@
 #include <binder/MemoryDealer.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
+#include <utils/Log.h>
 #include <utils/RefBase.h>
 #include <utils/Vector.h>
 
diff --git a/media/libstagefright/include/media/stagefright/MetaData.h b/media/libmediaextractor/include/media/stagefright/MetaData.h
similarity index 99%
rename from media/libstagefright/include/media/stagefright/MetaData.h
rename to media/libmediaextractor/include/media/stagefright/MetaData.h
index 5959e86..e4a84b7 100644
--- a/media/libstagefright/include/media/stagefright/MetaData.h
+++ b/media/libmediaextractor/include/media/stagefright/MetaData.h
@@ -22,12 +22,13 @@
 
 #include <stdint.h>
 
-#include <binder/Parcel.h>
 #include <utils/RefBase.h>
 #include <utils/String8.h>
 
 namespace android {
 
+class Parcel;
+
 // The following keys map to int32_t data unless indicated otherwise.
 enum {
     kKeyMIMEType          = 'mime',  // cstring
diff --git a/media/libmediametrics/MediaAnalyticsItem.cpp b/media/libmediametrics/MediaAnalyticsItem.cpp
index 2e7efad..dc2bec8 100644
--- a/media/libmediametrics/MediaAnalyticsItem.cpp
+++ b/media/libmediametrics/MediaAnalyticsItem.cpp
@@ -60,7 +60,7 @@
       mPkgVersionCode(0),
       mSessionID(MediaAnalyticsItem::SessionIDNone),
       mTimestamp(0),
-      mFinalized(0),
+      mFinalized(1),
       mPropCount(0), mPropSize(0), mProps(NULL)
 {
     mKey = MediaAnalyticsItem::kKeyNone;
@@ -72,7 +72,7 @@
       mPkgVersionCode(0),
       mSessionID(MediaAnalyticsItem::SessionIDNone),
       mTimestamp(0),
-      mFinalized(0),
+      mFinalized(1),
       mPropCount(0), mPropSize(0), mProps(NULL)
 {
     if (DEBUG_ALLOCATIONS) {
@@ -137,16 +137,6 @@
     return dst;
 }
 
-// so clients can send intermediate values to be overlaid later
-MediaAnalyticsItem &MediaAnalyticsItem::setFinalized(bool value) {
-    mFinalized = value;
-    return *this;
-}
-
-bool MediaAnalyticsItem::getFinalized() const {
-    return mFinalized;
-}
-
 MediaAnalyticsItem &MediaAnalyticsItem::setSessionID(MediaAnalyticsItem::SessionID_t id) {
     mSessionID = id;
     return *this;
@@ -636,7 +626,10 @@
     mPkgName = data.readCString();
     mPkgVersionCode = data.readInt64();
     mSessionID = data.readInt64();
+    // We no longer pay attention to user setting of finalized, BUT it's
+    // still part of the wire packet -- so read & discard.
     mFinalized = data.readInt32();
+    mFinalized = 1;
     mTimestamp = data.readInt64();
 
     int count = data.readInt32();
@@ -978,9 +971,6 @@
         mSessionID = incoming->mSessionID;
     }
 
-    // we always take the more recent 'finalized' value
-    setFinalized(incoming->getFinalized());
-
     // for each attribute from 'incoming', resolve appropriately
     int nattr = incoming->mPropCount;
     for (int i = 0 ; i < nattr; i++ ) {
diff --git a/media/libmediametrics/include/MediaAnalyticsItem.h b/media/libmediametrics/include/MediaAnalyticsItem.h
index 79ff093..263cde7 100644
--- a/media/libmediametrics/include/MediaAnalyticsItem.h
+++ b/media/libmediametrics/include/MediaAnalyticsItem.h
@@ -89,10 +89,6 @@
         MediaAnalyticsItem(Key);
         ~MediaAnalyticsItem();
 
-        // so clients can send intermediate values to be overlaid later
-        MediaAnalyticsItem &setFinalized(bool);
-        bool getFinalized() const;
-
         // SessionID ties multiple submissions for same key together
         // so that if video "height" and "width" are known at one point
         // and "framerate" is only known later, they can be be brought
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index dcd393b..4206647 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -527,4 +527,14 @@
     }
     return NO_INIT;
 }
+
+status_t MediaRecorderClient::getActiveMicrophones(
+        std::vector<media::MicrophoneInfo>* activeMicrophones) {
+    ALOGV("getActiveMicrophones");
+    Mutex::Autolock lock(mLock);
+    if (mRecorder != NULL) {
+        return mRecorder->getActiveMicrophones(activeMicrophones);
+    }
+    return NO_INIT;
+}
 }; // namespace android
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index 538b461..d2e681f 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -107,6 +107,8 @@
     virtual     status_t   setInputDevice(audio_port_handle_t deviceId);
     virtual     status_t   getRoutedDeviceId(audio_port_handle_t* deviceId);
     virtual     status_t   enableAudioDeviceCallback(bool enabled);
+    virtual     status_t   getActiveMicrophones(
+                              std::vector<media::MicrophoneInfo>* activeMicrophones);
 
 private:
     friend class           MediaPlayerService;  // for accessing private constructor
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 77eaefe..bc8d8c8 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -125,7 +125,6 @@
     if (mAnalyticsDirty && mAnalyticsItem != NULL) {
         updateMetrics();
         if (mAnalyticsItem->count() > 0) {
-            mAnalyticsItem->setFinalized(true);
             mAnalyticsItem->selfrecord();
         }
         delete mAnalyticsItem;
@@ -185,14 +184,12 @@
     if (mAnalyticsDirty && mAnalyticsItem != NULL) {
         updateMetrics();
         if (mAnalyticsItem->count() > 0) {
-            mAnalyticsItem->setFinalized(true);
             mAnalyticsItem->selfrecord();
         }
         delete mAnalyticsItem;
         mAnalyticsItem = NULL;
     }
     mAnalyticsItem = new MediaAnalyticsItem(kKeyRecorder);
-    (void) mAnalyticsItem->generateSessionID();
     mAnalyticsDirty = false;
 }
 
@@ -2163,6 +2160,15 @@
     return NO_ERROR;
 }
 
+status_t StagefrightRecorder::getActiveMicrophones(
+        std::vector<media::MicrophoneInfo>* activeMicrophones) {
+    if (mAudioSourceNode != 0) {
+        return mAudioSourceNode->getActiveMicrophones(activeMicrophones);
+    }
+    return NO_INIT;
+}
+
+
 status_t StagefrightRecorder::dump(
         int fd, const Vector<String16>& args) const {
     ALOGV("dump");
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index ec7e8ed..18c9256 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -76,6 +76,8 @@
     virtual status_t getRoutedDeviceId(audio_port_handle_t* deviceId);
     virtual void setAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback);
     virtual status_t enableAudioDeviceCallback(bool enabled);
+    virtual status_t getActiveMicrophones(std::vector<media::MicrophoneInfo>* activeMicrophones);
+
 
 private:
     mutable Mutex mLock;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 8aa06fc..b3fd00a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -91,7 +91,6 @@
 
     // set up an analytics record
     mAnalyticsItem = new MediaAnalyticsItem(kKeyPlayer);
-    mAnalyticsItem->generateSessionID();
 
     mLooper->start(
             false, /* runOnCallingThread */
@@ -617,14 +616,12 @@
     // So the canonical "empty" record has 3 elements in it.
     if (mAnalyticsItem->count() > 3) {
 
-        mAnalyticsItem->setFinalized(true);
         mAnalyticsItem->selfrecord();
 
         // re-init in case we prepare() and start() again.
         delete mAnalyticsItem ;
         mAnalyticsItem = new MediaAnalyticsItem("nuplayer");
         if (mAnalyticsItem) {
-            mAnalyticsItem->generateSessionID();
             mAnalyticsItem->setUid(mClientUid);
         }
     } else {
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 90f6ed7..c5abe9b 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -26,6 +26,28 @@
     shared_libs: ["libmedia"],
 }
 
+cc_library_static {
+    name: "libstagefright_metadatautils",
+
+    srcs: ["MetaDataUtils.cpp"],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    shared_libs: ["libmedia"],
+}
+
 cc_library_shared {
     name: "libstagefright",
 
@@ -78,8 +100,8 @@
         "StagefrightMetadataRetriever.cpp",
         "SurfaceMediaSource.cpp",
         "SurfaceUtils.cpp",
-        "ThrottledSource.cpp",
         "Utils.cpp",
+        "ThrottledSource.cpp",
         "VideoFrameScheduler.cpp",
     ],
 
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index b8da980..70ce38c 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -498,4 +498,12 @@
     return NO_INIT;
 }
 
+status_t AudioSource::getActiveMicrophones(
+        std::vector<media::MicrophoneInfo>* activeMicrophones) {
+    if (mRecord != 0) {
+        return mRecord->getActiveMicrophones(activeMicrophones);
+    }
+    return NO_INIT;
+}
+
 }  // namespace android
diff --git a/media/libstagefright/CCodecBufferChannel.cpp b/media/libstagefright/CCodecBufferChannel.cpp
index 2f4a7ea..04f7593 100644
--- a/media/libstagefright/CCodecBufferChannel.cpp
+++ b/media/libstagefright/CCodecBufferChannel.cpp
@@ -312,6 +312,7 @@
                 mBufferArray[i].available = false;
                 *index = i;
                 *buffer = mBufferArray[i].clientBuffer;
+                (*buffer)->meta()->clear();
                 (*buffer)->setRange(0, (*buffer)->capacity());
                 return true;
             }
@@ -487,6 +488,7 @@
                 *index = i;
                 *codecBuffer = mBufferArray[i].clientBuffer;
                 (*codecBuffer)->setFormat(mFormat);
+                (*codecBuffer)->meta()->clear();
                 mBufferArray[i].compBuffer = buffer;
                 mBufferArray[i].available = false;
                 return true;
@@ -512,6 +514,7 @@
                 *index = i;
                 *codecBuffer = mBufferArray[i].clientBuffer;
                 (*codecBuffer)->setFormat(mFormat);
+                (*codecBuffer)->meta()->clear();
                 mBufferArray[i].available = false;
                 return true;
             }
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 559b108..56ac3ed 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -502,7 +502,6 @@
     // set up our new record, get a sessionID, put it into the in-progress list
     mAnalyticsItem = new MediaAnalyticsItem(kCodecKeyName);
     if (mAnalyticsItem != NULL) {
-        (void) mAnalyticsItem->generateSessionID();
         // don't record it yet; only at the end, when we have decided that we have
         // data worth writing (e.g. .count() > 0)
     }
@@ -512,7 +511,6 @@
     if (mAnalyticsItem != NULL) {
         // don't log empty records
         if (mAnalyticsItem->count() > 0) {
-            mAnalyticsItem->setFinalized(true);
             mAnalyticsItem->selfrecord();
         }
         delete mAnalyticsItem;
diff --git a/media/libstagefright/MetaDataUtils.cpp b/media/libstagefright/MetaDataUtils.cpp
new file mode 100644
index 0000000..fd51a2c
--- /dev/null
+++ b/media/libstagefright/MetaDataUtils.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2018 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 "MetaDataUtils"
+
+#include <media/stagefright/foundation/avc_utils.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaDataUtils.h>
+
+namespace android {
+
+sp<MetaData> MakeAVCCodecSpecificData(const sp<ABuffer> &accessUnit) {
+    int32_t width;
+    int32_t height;
+    int32_t sarWidth;
+    int32_t sarHeight;
+    sp<ABuffer> csd = MakeAVCCodecSpecificData(accessUnit, &width, &height, &sarWidth, &sarHeight);
+    if (csd == nullptr) {
+        return nullptr;
+    }
+    sp<MetaData> meta = new MetaData;
+    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+
+    meta->setData(kKeyAVCC, kTypeAVCC, csd->data(), csd->size());
+    meta->setInt32(kKeyWidth, width);
+    meta->setInt32(kKeyHeight, height);
+    if (sarWidth > 0 && sarHeight > 0) {
+        meta->setInt32(kKeySARWidth, sarWidth);
+        meta->setInt32(kKeySARHeight, sarHeight);
+    }
+    return meta;
+}
+
+sp<MetaData> MakeAACCodecSpecificData(
+        unsigned profile, unsigned sampling_freq_index,
+        unsigned channel_configuration) {
+    int32_t sampleRate;
+    int32_t channelCount;
+    sp<ABuffer> csd = MakeAACCodecSpecificData(profile, sampling_freq_index,
+            channel_configuration, &sampleRate, &channelCount);
+    if (csd == nullptr) {
+        return nullptr;
+    }
+    sp<MetaData> meta = new MetaData;
+    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
+
+    meta->setInt32(kKeySampleRate, sampleRate);
+    meta->setInt32(kKeyChannelCount, channelCount);
+
+    meta->setData(kKeyESDS, 0, csd->data(), csd->size());
+    return meta;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/RemoteMediaExtractor.cpp b/media/libstagefright/RemoteMediaExtractor.cpp
index 43d33e5..3ebee51 100644
--- a/media/libstagefright/RemoteMediaExtractor.cpp
+++ b/media/libstagefright/RemoteMediaExtractor.cpp
@@ -44,7 +44,6 @@
     mAnalyticsItem = nullptr;
     if (MEDIA_LOG) {
         mAnalyticsItem = new MediaAnalyticsItem(kKeyExtractor);
-        (void) mAnalyticsItem->generateSessionID();
 
         // track the container format (mpeg, aac, wvm, etc)
         size_t ntracks = extractor->countTracks();
@@ -73,7 +72,6 @@
     if (MEDIA_LOG) {
         if (mAnalyticsItem != nullptr) {
             if (mAnalyticsItem->count() > 0) {
-                mAnalyticsItem->setFinalized(true);
                 mAnalyticsItem->selfrecord();
             }
         }
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 53699ef..4a93051 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -667,7 +667,7 @@
         if (!strncasecmp("image/", mime, 6)) {
             int32_t gridWidth, gridHeight, gridRows, gridCols;
             if (meta->findInt32(kKeyGridWidth, &gridWidth)
-                    && meta->findInt32(kKeyHeight, &gridHeight)
+                    && meta->findInt32(kKeyGridHeight, &gridHeight)
                     && meta->findInt32(kKeyGridRows, &gridRows)
                     && meta->findInt32(kKeyGridCols, &gridCols)) {
                 msg->setInt32("grid-width", gridWidth);
diff --git a/media/libstagefright/codec2/vndk/C2Store.cpp b/media/libstagefright/codec2/vndk/C2Store.cpp
index 496cbe1..a49fd24 100644
--- a/media/libstagefright/codec2/vndk/C2Store.cpp
+++ b/media/libstagefright/codec2/vndk/C2Store.cpp
@@ -407,6 +407,7 @@
     mComponents.emplace("c2.google.avc.encoder", "libstagefright_soft_c2avcenc.so");
     mComponents.emplace("c2.google.aac.decoder", "libstagefright_soft_c2aacdec.so");
     mComponents.emplace("c2.google.aac.encoder", "libstagefright_soft_c2aacenc.so");
+    mComponents.emplace("c2.google.mp3.decoder", "libstagefright_soft_c2mp3dec.so");
 }
 
 c2_status_t C2PlatformComponentStore::copyBuffer(
diff --git a/media/libstagefright/codecs/avcenc/C2SoftAvcEnc.h b/media/libstagefright/codecs/avcenc/C2SoftAvcEnc.h
index 5b2a514..a113436 100644
--- a/media/libstagefright/codecs/avcenc/C2SoftAvcEnc.h
+++ b/media/libstagefright/codecs/avcenc/C2SoftAvcEnc.h
@@ -17,6 +17,8 @@
 #ifndef C2_SOFT_AVC_ENC_H__
 #define C2_SOFT_AVC_ENC_H__
 
+#include <map>
+
 #include <media/stagefright/foundation/ABase.h>
 #include <utils/Vector.h>
 
diff --git a/media/libstagefright/codecs/mp3dec/Android.bp b/media/libstagefright/codecs/mp3dec/Android.bp
index e6eb32b..9e41d17 100644
--- a/media/libstagefright/codecs/mp3dec/Android.bp
+++ b/media/libstagefright/codecs/mp3dec/Android.bp
@@ -119,6 +119,50 @@
     compile_multilib: "32",
 }
 
+cc_library_shared {
+    name: "libstagefright_soft_c2mp3dec",
+//    vendor_available: true,
+//    vndk: {
+//        enabled: true,
+//    },
+
+    srcs: ["C2SoftMP3.cpp"],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
+    local_include_dirs: [
+        "src",
+        "include",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    static_libs: [
+        "libstagefright_mp3dec"
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libutils",
+        "libstagefright_codec2",
+        "libstagefright_codec2_vndk",
+        "libstagefright_foundation",
+        "libstagefright_simple_c2component",
+    ],
+}
+
 //###############################################################################
 cc_test {
     name: "libstagefright_mp3dec_test",
diff --git a/media/libstagefright/codecs/mp3dec/C2SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/C2SoftMP3.cpp
new file mode 100644
index 0000000..c34a6f0
--- /dev/null
+++ b/media/libstagefright/codecs/mp3dec/C2SoftMP3.cpp
@@ -0,0 +1,431 @@
+/*
+ * Copyright (C) 2018 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 "C2SoftMP3"
+#include <utils/Log.h>
+
+#include "pvmp3decoder_api.h"
+
+#include "C2SoftMP3.h"
+
+#include <C2PlatformSupport.h>
+#include <SimpleC2Interface.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+
+#include <numeric>
+
+namespace android {
+
+C2SoftMP3::C2SoftMP3(const char *name, c2_node_id_t id)
+    : SimpleC2Component(
+            SimpleC2Interface::Builder(name, id)
+            .inputFormat(C2FormatCompressed)
+            .outputFormat(C2FormatAudio)
+            .build()),
+      mConfig(nullptr),
+      mDecoderBuf(nullptr) {
+}
+
+C2SoftMP3::~C2SoftMP3() {
+    onRelease();
+}
+
+c2_status_t C2SoftMP3::onInit() {
+    status_t err = initDecoder();
+    return err == OK ? C2_OK : C2_NO_MEMORY;
+}
+
+c2_status_t C2SoftMP3::onStop() {
+    // Make sure that the next buffer output does not still
+    // depend on fragments from the last one decoded.
+    pvmp3_InitDecoder(mConfig, mDecoderBuf);
+    mSignalledError = false;
+    mIsFirst = true;
+    mSignalledOutputEos = false;
+
+    return C2_OK;
+}
+
+void C2SoftMP3::onReset() {
+    (void)onStop();
+}
+
+void C2SoftMP3::onRelease() {
+    if (mDecoderBuf) {
+        free(mDecoderBuf);
+        mDecoderBuf = nullptr;
+    }
+
+    if (mConfig) {
+        delete mConfig;
+        mConfig = nullptr;
+    }
+}
+
+status_t C2SoftMP3::initDecoder() {
+    mConfig = new tPVMP3DecoderExternal{};
+    if (!mConfig) return NO_MEMORY;
+    mConfig->equalizerType = flat;
+    mConfig->crcEnabled = false;
+
+    size_t memRequirements = pvmp3_decoderMemRequirements();
+    mDecoderBuf = malloc(memRequirements);
+    if (!mDecoderBuf) return NO_MEMORY;
+
+    pvmp3_InitDecoder(mConfig, mDecoderBuf);
+
+    mNumChannels = 2;
+    mSamplingRate = 44100;
+    mIsFirst = true;
+    mSignalledError = false;
+    mSignalledOutputEos = false;
+
+    return OK;
+}
+
+/* The below code is borrowed from ./test/mp3reader.cpp */
+static bool parseMp3Header(uint32_t header, size_t *frame_size,
+                           uint32_t *out_sampling_rate = nullptr,
+                           uint32_t *out_channels = nullptr,
+                           uint32_t *out_bitrate = nullptr,
+                           uint32_t *out_num_samples = nullptr) {
+    *frame_size = 0;
+    if (out_sampling_rate) *out_sampling_rate = 0;
+    if (out_channels) *out_channels = 0;
+    if (out_bitrate) *out_bitrate = 0;
+    if (out_num_samples) *out_num_samples = 1152;
+
+    if ((header & 0xffe00000) != 0xffe00000) return false;
+
+    unsigned version = (header >> 19) & 3;
+    if (version == 0x01) return false;
+
+    unsigned layer = (header >> 17) & 3;
+    if (layer == 0x00) return false;
+
+    unsigned bitrate_index = (header >> 12) & 0x0f;
+    if (bitrate_index == 0 || bitrate_index == 0x0f) return false;
+
+    unsigned sampling_rate_index = (header >> 10) & 3;
+    if (sampling_rate_index == 3) return false;
+
+    static const int kSamplingRateV1[] = { 44100, 48000, 32000 };
+    int sampling_rate = kSamplingRateV1[sampling_rate_index];
+    if (version == 2 /* V2 */) {
+        sampling_rate /= 2;
+    } else if (version == 0 /* V2.5 */) {
+        sampling_rate /= 4;
+    }
+
+    unsigned padding = (header >> 9) & 1;
+
+    if (layer == 3) { // layer I
+        static const int kBitrateV1[] =
+        {
+            32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448
+        };
+        static const int kBitrateV2[] =
+        {
+            32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256
+        };
+
+        int bitrate = (version == 3 /* V1 */) ? kBitrateV1[bitrate_index - 1] :
+                kBitrateV2[bitrate_index - 1];
+
+        if (out_bitrate) {
+            *out_bitrate = bitrate;
+        }
+        *frame_size = (12000 * bitrate / sampling_rate + padding) * 4;
+        if (out_num_samples) {
+            *out_num_samples = 384;
+        }
+    } else { // layer II or III
+        static const int kBitrateV1L2[] =
+        {
+            32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384
+        };
+
+        static const int kBitrateV1L3[] =
+        {
+            32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320
+        };
+
+        static const int kBitrateV2[] =
+        {
+            8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160
+        };
+
+        int bitrate;
+        if (version == 3 /* V1 */) {
+            bitrate = (layer == 2 /* L2 */) ? kBitrateV1L2[bitrate_index - 1] :
+                    kBitrateV1L3[bitrate_index - 1];
+
+            if (out_num_samples) {
+                *out_num_samples = 1152;
+            }
+        } else { // V2 (or 2.5)
+            bitrate = kBitrateV2[bitrate_index - 1];
+            if (out_num_samples) {
+                *out_num_samples = (layer == 1 /* L3 */) ? 576 : 1152;
+            }
+        }
+
+        if (out_bitrate) {
+            *out_bitrate = bitrate;
+        }
+
+        if (version == 3 /* V1 */) {
+            *frame_size = 144000 * bitrate / sampling_rate + padding;
+        } else { // V2 or V2.5
+            size_t tmp = (layer == 1 /* L3 */) ? 72000 : 144000;
+            *frame_size = tmp * bitrate / sampling_rate + padding;
+        }
+    }
+
+    if (out_sampling_rate) {
+        *out_sampling_rate = sampling_rate;
+    }
+
+    if (out_channels) {
+        int channel_mode = (header >> 6) & 3;
+
+        *out_channels = (channel_mode == 3) ? 1 : 2;
+    }
+
+    return true;
+}
+
+static uint32_t U32_AT(const uint8_t *ptr) {
+    return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3];
+}
+
+static status_t calculateOutSize(uint8 *header, size_t inSize,
+                                 std::vector<size_t> *decodedSizes) {
+    uint32_t channels;
+    uint32_t numSamples;
+    size_t frameSize;
+    size_t totalInSize = 0;
+
+    while (totalInSize + 4 < inSize) {
+        if (!parseMp3Header(U32_AT(header + totalInSize), &frameSize,
+                            nullptr, &channels, nullptr, &numSamples)) {
+            ALOGE("Error in parse mp3 header during outSize estimation");
+            return UNKNOWN_ERROR;
+        }
+        totalInSize += frameSize;
+        decodedSizes->push_back(numSamples * channels * sizeof(int16_t));
+    }
+
+    if (decodedSizes->empty()) return UNKNOWN_ERROR;
+
+    return OK;
+}
+
+c2_status_t C2SoftMP3::onFlush_sm() {
+    return onStop();
+}
+
+c2_status_t C2SoftMP3::drain(
+        uint32_t drainMode,
+        const std::shared_ptr<C2BlockPool> &pool) {
+    (void) pool;
+    if (drainMode == NO_DRAIN) {
+        ALOGW("drain with NO_DRAIN: no-op");
+        return C2_OK;
+    }
+    if (drainMode == DRAIN_CHAIN) {
+        ALOGW("DRAIN_CHAIN not supported");
+        return C2_OMITTED;
+    }
+
+    return C2_OK;
+}
+
+// TODO: Can overall error checking be improved? As in the check for validity of
+//       work, pool ptr, work->input.buffers.size() == 1, ...
+// TODO: Gapless playback: decoder has a delay of 529 samples. For the first
+//       frame we intend to remove 529 samples worth of data. When this is
+//       done it is going to effect the timestamps of future frames. This
+//       timestamp correction is handled by the client or plugin? Soft omx mp3
+//       plugin also has this problem
+// TODO: Blind removal of 529 samples from the output may not work. Because
+//       mpeg layer 1 frame size is 384 samples per frame. This should introduce
+//       negative values and can cause SEG faults. Soft omx mp3 plugin can have
+//       this problem (CHECK!)
+void C2SoftMP3::process(
+        const std::unique_ptr<C2Work> &work,
+        const std::shared_ptr<C2BlockPool> &pool) {
+    work->result = C2_OK;
+    work->workletsProcessed = 0u;
+    if (mSignalledError || mSignalledOutputEos) {
+        work->result = C2_BAD_VALUE;
+        return;
+    }
+
+    const C2ConstLinearBlock &inBuffer = work->input.buffers[0]->data().linearBlocks().front();
+    bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
+    size_t inOffset = inBuffer.offset();
+    size_t inSize = inBuffer.size();
+    C2ReadView rView = inBuffer.map().get();
+    if (inSize && rView.error()) {
+        ALOGE("read view map failed %d", rView.error());
+        work->result = C2_CORRUPTED;
+        return;
+    }
+
+    if (inSize == 0) {
+        work->worklets.front()->output.flags = work->input.flags;
+        work->worklets.front()->output.buffers.clear();
+        work->worklets.front()->output.ordinal = work->input.ordinal;
+        work->workletsProcessed = 1u;
+        if (eos) {
+            mSignalledOutputEos = true;
+            ALOGV("signalled EOS");
+        }
+        return;
+    }
+    ALOGV("in buffer attr. size %zu timestamp %d frameindex %d", inSize,
+          (int)work->input.ordinal.timestamp.peeku(), (int)work->input.ordinal.frameIndex.peeku());
+
+    size_t calOutSize;
+    std::vector<size_t> decodedSizes;
+    if (OK != calculateOutSize(const_cast<uint8 *>(rView.data() + inOffset),
+                               inSize, &decodedSizes)) {
+        work->result = C2_CORRUPTED;
+        return;
+    }
+    calOutSize = std::accumulate(decodedSizes.begin(), decodedSizes.end(), 0);
+    std::shared_ptr<C2LinearBlock> block;
+    C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
+    c2_status_t err = pool->fetchLinearBlock(calOutSize, usage, &block);
+    if (err != C2_OK) {
+        ALOGE("fetchLinearBlock for Output failed with status %d", err);
+        work->result = C2_NO_MEMORY;
+        return;
+    }
+    C2WriteView wView = block->map().get();
+    if (wView.error()) {
+        ALOGE("write view map failed %d", wView.error());
+        work->result = C2_CORRUPTED;
+        return;
+    }
+
+    int outSize = 0;
+    int outOffset = 0;
+    auto it = decodedSizes.begin();
+    while (inOffset < inSize) {
+        if (it == decodedSizes.end()) {
+            ALOGE("unexpected trailing bytes, ignoring them");
+            break;
+        }
+
+        mConfig->pInputBuffer = const_cast<uint8 *>(rView.data() + inOffset);
+        mConfig->inputBufferCurrentLength = (inSize - inOffset);
+        mConfig->inputBufferMaxLength = 0;
+        mConfig->inputBufferUsedLength = 0;
+        mConfig->outputFrameSize = (calOutSize - outSize);
+        mConfig->pOutputBuffer = reinterpret_cast<int16_t *> (wView.data() + outSize);
+
+        ERROR_CODE decoderErr;
+        if ((decoderErr = pvmp3_framedecoder(mConfig, mDecoderBuf))
+                != NO_DECODING_ERROR) {
+            ALOGE("mp3 decoder returned error %d", decoderErr);
+            if (decoderErr != NO_ENOUGH_MAIN_DATA_ERROR
+                    && decoderErr != SIDE_INFO_ERROR) {
+                mSignalledError = true;
+                work->result = C2_CORRUPTED;
+                return;
+            }
+
+            // This is recoverable, just ignore the current frame and
+            // play silence instead.
+            ALOGV("ignoring error and sending silence");
+            if (mConfig->outputFrameSize == 0) {
+                mConfig->outputFrameSize = *it / sizeof(int16_t);
+            }
+            memset(mConfig->pOutputBuffer, 0, mConfig->outputFrameSize * sizeof(int16_t));
+        } else if (mConfig->samplingRate != mSamplingRate
+                || mConfig->num_channels != mNumChannels) {
+            mSamplingRate = mConfig->samplingRate;
+            mNumChannels = mConfig->num_channels;
+        }
+        if (*it != mConfig->outputFrameSize * sizeof(int16_t)) {
+            ALOGE("panic, parsed size does not match decoded size");
+            mSignalledError = true;
+            work->result = C2_CORRUPTED;
+            return;
+        }
+        outSize += mConfig->outputFrameSize * sizeof(int16_t);
+        inOffset += mConfig->inputBufferUsedLength;
+        it++;
+    }
+    if (mIsFirst) {
+        mIsFirst = false;
+        // The decoder delay is 529 samples, so trim that many samples off
+        // the start of the first output buffer. This essentially makes this
+        // decoder have zero delay, which the rest of the pipeline assumes.
+        outOffset = kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t);
+    }
+    ALOGV("out buffer attr. offset %d size %d", outOffset, outSize);
+    decodedSizes.clear();
+    work->worklets.front()->output.flags = work->input.flags;
+    work->worklets.front()->output.buffers.clear();
+    work->worklets.front()->output.buffers.push_back(createLinearBuffer(block, outOffset, outSize));
+    work->worklets.front()->output.ordinal = work->input.ordinal;
+    work->workletsProcessed = 1u;
+    if (eos) {
+        mSignalledOutputEos = true;
+        ALOGV("signalled EOS");
+    }
+}
+
+class C2SoftMp3DecFactory : public C2ComponentFactory {
+public:
+    virtual c2_status_t createComponent(
+            c2_node_id_t id, std::shared_ptr<C2Component>* const component,
+            std::function<void(::android::C2Component*)> deleter) override {
+        *component = std::shared_ptr<C2Component>(new C2SoftMP3("mp3", id), deleter);
+        return C2_OK;
+    }
+
+    virtual c2_status_t createInterface(
+            c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
+            std::function<void(::android::C2ComponentInterface*)> deleter) override {
+        *interface =
+                SimpleC2Interface::Builder("mp3", id, deleter)
+                .inputFormat(C2FormatCompressed)
+                .outputFormat(C2FormatAudio)
+                .build();
+        return C2_OK;
+    }
+
+    virtual ~C2SoftMp3DecFactory() override = default;
+};
+
+}  // namespace android
+
+extern "C" ::android::C2ComponentFactory* CreateCodec2Factory() {
+    ALOGV("in %s", __func__);
+    return new ::android::C2SoftMp3DecFactory();
+}
+
+extern "C" void DestroyCodec2Factory(::android::C2ComponentFactory* factory) {
+    ALOGV("in %s", __func__);
+    delete factory;
+}
+
diff --git a/media/libstagefright/codecs/mp3dec/C2SoftMP3.h b/media/libstagefright/codecs/mp3dec/C2SoftMP3.h
new file mode 100644
index 0000000..ad974bd
--- /dev/null
+++ b/media/libstagefright/codecs/mp3dec/C2SoftMP3.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2018 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 C2_SOFT_MP3_H_
+#define C2_SOFT_MP3_H_
+
+#include <SimpleC2Component.h>
+
+#include <media/stagefright/foundation/ABase.h>
+
+struct tPVMP3DecoderExternal;
+
+bool parseMp3Header(uint32_t header, size_t *frame_size,
+                    uint32_t *out_sampling_rate = nullptr,
+                    uint32_t *out_channels = nullptr,
+                    uint32_t *out_bitrate = nullptr,
+                    uint32_t *out_num_samples = nullptr);
+
+namespace android {
+
+struct C2SoftMP3 : public SimpleC2Component {
+    C2SoftMP3(const char *name, c2_node_id_t id);
+    virtual ~C2SoftMP3();
+
+    // From SimpleC2Component
+    c2_status_t onInit() override;
+    c2_status_t onStop() override;
+    void onReset() override;
+    void onRelease() override;
+    c2_status_t onFlush_sm() override;
+    void process(
+            const std::unique_ptr<C2Work> &work,
+            const std::shared_ptr<C2BlockPool> &pool) override;
+    c2_status_t drain(
+            uint32_t drainMode,
+            const std::shared_ptr<C2BlockPool> &pool) override;
+
+private:
+    enum {
+        kPVMP3DecoderDelay = 529 // samples
+    };
+
+    tPVMP3DecoderExternal *mConfig;
+    void *mDecoderBuf;
+
+    int32_t mNumChannels;
+    int32_t mSamplingRate;
+    bool mIsFirst;
+    bool mSignalledError;
+    bool mSignalledOutputEos;
+
+    status_t initDecoder();
+
+    DISALLOW_EVIL_CONSTRUCTORS(C2SoftMP3);
+};
+
+}  // namespace android
+
+#endif  // C2_SOFT_MP3_H_
diff --git a/media/libstagefright/foundation/Android.bp b/media/libstagefright/foundation/Android.bp
index 2258e2c..b343c16 100644
--- a/media/libstagefright/foundation/Android.bp
+++ b/media/libstagefright/foundation/Android.bp
@@ -64,7 +64,6 @@
         "ColorUtils.cpp",
         "MediaDefs.cpp",
         "MediaKeys.cpp",
-        "MetaData.cpp",
         "ParsedMessage.cpp",
         "avc_utils.cpp",
         "base64.cpp",
diff --git a/media/libstagefright/foundation/avc_utils.cpp b/media/libstagefright/foundation/avc_utils.cpp
index bfaeb21..b58474c 100644
--- a/media/libstagefright/foundation/avc_utils.cpp
+++ b/media/libstagefright/foundation/avc_utils.cpp
@@ -383,7 +383,9 @@
     }
 }
 
-sp<MetaData> MakeAVCCodecSpecificData(const sp<ABuffer> &accessUnit) {
+sp<ABuffer> MakeAVCCodecSpecificData(
+        const sp<ABuffer> &accessUnit, int32_t *width, int32_t *height,
+        int32_t *sarWidth, int32_t *sarHeight) {
     const uint8_t *data = accessUnit->data();
     size_t size = accessUnit->size();
 
@@ -392,10 +394,8 @@
         return NULL;
     }
 
-    int32_t width, height;
-    int32_t sarWidth, sarHeight;
     FindAVCDimensions(
-            seqParamSet, &width, &height, &sarWidth, &sarHeight);
+            seqParamSet, width, height, sarWidth, sarHeight);
 
     sp<ABuffer> picParamSet = FindNAL(data, size, 8);
     CHECK(picParamSet != NULL);
@@ -434,38 +434,32 @@
     hexdump(seqParamSet->data(), seqParamSet->size());
 #endif
 
-    sp<MetaData> meta = new MetaData;
-    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
 
-    meta->setData(kKeyAVCC, kTypeAVCC, csd->data(), csd->size());
-    meta->setInt32(kKeyWidth, width);
-    meta->setInt32(kKeyHeight, height);
-
-    if ((sarWidth > 0 && sarHeight > 0) && (sarWidth != 1 || sarHeight != 1)) {
-        // We treat *:0 and 0:* (unspecified) as 1:1.
-
-        meta->setInt32(kKeySARWidth, sarWidth);
-        meta->setInt32(kKeySARHeight, sarHeight);
-
-        ALOGI("found AVC codec config (%d x %d, %s-profile level %d.%d) "
-              "SAR %d : %d",
-             width,
-             height,
-             AVCProfileToString(profile),
-             level / 10,
-             level % 10,
-             sarWidth,
-             sarHeight);
-    } else {
-        ALOGI("found AVC codec config (%d x %d, %s-profile level %d.%d)",
-             width,
-             height,
-             AVCProfileToString(profile),
-             level / 10,
-             level % 10);
+    if (sarWidth != nullptr && sarHeight != nullptr) {
+        if ((*sarWidth > 0 && *sarHeight > 0) && (*sarWidth != 1 || *sarHeight != 1)) {
+            ALOGI("found AVC codec config (%d x %d, %s-profile level %d.%d) "
+                    "SAR %d : %d",
+                    *width,
+                    *height,
+                    AVCProfileToString(profile),
+                    level / 10,
+                    level % 10,
+                    *sarWidth,
+                    *sarHeight);
+        } else {
+            // We treat *:0 and 0:* (unspecified) as 1:1.
+            *sarWidth = 0;
+            *sarHeight = 0;
+            ALOGI("found AVC codec config (%d x %d, %s-profile level %d.%d)",
+                    *width,
+                    *height,
+                    AVCProfileToString(profile),
+                    level / 10,
+                    level % 10);
+        }
     }
 
-    return meta;
+    return csd;
 }
 
 bool IsIDR(const uint8_t *data, size_t size) {
@@ -543,19 +537,17 @@
     return layerId;
 }
 
-sp<MetaData> MakeAACCodecSpecificData(
+sp<ABuffer> MakeAACCodecSpecificData(
         unsigned profile, unsigned sampling_freq_index,
-        unsigned channel_configuration) {
-    sp<MetaData> meta = new MetaData;
-    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
-
+        unsigned channel_configuration, int32_t *sampleRate,
+        int32_t *channelCount) {
     CHECK_LE(sampling_freq_index, 11u);
     static const int32_t kSamplingFreq[] = {
         96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
         16000, 12000, 11025, 8000
     };
-    meta->setInt32(kKeySampleRate, kSamplingFreq[sampling_freq_index]);
-    meta->setInt32(kKeyChannelCount, channel_configuration);
+    *sampleRate = kSamplingFreq[sampling_freq_index];
+    *channelCount = channel_configuration;
 
     static const uint8_t kStaticESDS[] = {
         0x03, 22,
@@ -585,9 +577,7 @@
     csd->data()[sizeof(kStaticESDS) + 1] =
         ((sampling_freq_index << 7) & 0x80) | (channel_configuration << 3);
 
-    meta->setData(kKeyESDS, 0, csd->data(), csd->size());
-
-    return meta;
+    return csd;
 }
 
 bool ExtractDimensionsFromVOLHeader(
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/avc_utils.h b/media/libstagefright/foundation/include/media/stagefright/foundation/avc_utils.h
index a939f12..2ca66fb 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/avc_utils.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/avc_utils.h
@@ -80,8 +80,9 @@
         const uint8_t **nalStart, size_t *nalSize,
         bool startCodeFollows = false);
 
-class MetaData;
-sp<MetaData> MakeAVCCodecSpecificData(const sp<ABuffer> &accessUnit);
+sp<ABuffer> MakeAVCCodecSpecificData(
+        const sp<ABuffer> &accessUnit, int32_t *width, int32_t *height,
+        int32_t *sarWidth = nullptr, int32_t *sarHeight = nullptr);
 
 bool IsIDR(const uint8_t *data, size_t size);
 bool IsAVCReferenceFrame(const sp<ABuffer> &accessUnit);
@@ -89,9 +90,10 @@
 
 const char *AVCProfileToString(uint8_t profile);
 
-sp<MetaData> MakeAACCodecSpecificData(
+sp<ABuffer> MakeAACCodecSpecificData(
         unsigned profile, unsigned sampling_freq_index,
-        unsigned channel_configuration);
+        unsigned channel_configuration, int32_t *sampleRate,
+        int32_t *channelCount);
 
 // Given an MPEG4 video VOL-header chunk (starting with 0x00 0x00 0x01 0x2?)
 // parse it and fill in dimensions, returns true iff successful.
diff --git a/media/libstagefright/httplive/Android.bp b/media/libstagefright/httplive/Android.bp
index de560b6..f64e437 100644
--- a/media/libstagefright/httplive/Android.bp
+++ b/media/libstagefright/httplive/Android.bp
@@ -47,6 +47,7 @@
 
     static_libs: [
         "libstagefright_id3",
+        "libstagefright_metadatautils",
         "libstagefright_mpeg2support",
     ],
 
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index b46d923..55fc680 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -35,6 +35,7 @@
 #include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
+#include <media/stagefright/MetaDataUtils.h>
 #include <media/stagefright/Utils.h>
 
 #include <ctype.h>
diff --git a/media/libstagefright/include/FrameDecoder.h b/media/libstagefright/include/FrameDecoder.h
index 6f07838..c40324b 100644
--- a/media/libstagefright/include/FrameDecoder.h
+++ b/media/libstagefright/include/FrameDecoder.h
@@ -17,6 +17,9 @@
 #ifndef FRAME_DECODER_H_
 #define FRAME_DECODER_H_
 
+#include <memory>
+#include <vector>
+
 #include <media/stagefright/foundation/AString.h>
 #include <media/stagefright/foundation/ABase.h>
 #include <media/MediaSource.h>
diff --git a/media/libstagefright/include/media/stagefright/AudioSource.h b/media/libstagefright/include/media/stagefright/AudioSource.h
index 9414aab..f66b92d 100644
--- a/media/libstagefright/include/media/stagefright/AudioSource.h
+++ b/media/libstagefright/include/media/stagefright/AudioSource.h
@@ -21,11 +21,14 @@
 #include <media/AudioRecord.h>
 #include <media/AudioSystem.h>
 #include <media/MediaSource.h>
+#include <media/MicrophoneInfo.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <utils/List.h>
 
 #include <system/audio.h>
 
+#include <vector>
+
 namespace android {
 
 class AudioRecord;
@@ -64,6 +67,9 @@
     status_t addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback);
     status_t removeAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback);
 
+    status_t getActiveMicrophones(std::vector<media::MicrophoneInfo>* activeMicrophones);
+
+
 protected:
     virtual ~AudioSource();
 
diff --git a/media/libstagefright/include/media/stagefright/MetaData.h b/media/libstagefright/include/media/stagefright/MetaData.h
new file mode 120000
index 0000000..160f8d3
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/MetaData.h
@@ -0,0 +1 @@
+../../../../libmediaextractor/include/media/stagefright/MetaData.h
\ No newline at end of file
diff --git a/media/libstagefright/include/media/stagefright/MetaDataUtils.h b/media/libstagefright/include/media/stagefright/MetaDataUtils.h
new file mode 100644
index 0000000..7c18bc2
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/MetaDataUtils.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2018 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 META_DATA_UTILS_H_
+
+#define META_DATA_UTILS_H_
+
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+struct ABuffer;
+sp<MetaData> MakeAVCCodecSpecificData(const sp<ABuffer> &accessUnit);
+sp<MetaData> MakeAACCodecSpecificData(unsigned profile, unsigned sampling_freq_index,
+        unsigned channel_configuration);
+
+}  // namespace android
+
+#endif  // META_DATA_UTILS_H_
diff --git a/media/libstagefright/mpeg2ts/Android.bp b/media/libstagefright/mpeg2ts/Android.bp
index 7654eb3..0b2a48f 100644
--- a/media/libstagefright/mpeg2ts/Android.bp
+++ b/media/libstagefright/mpeg2ts/Android.bp
@@ -37,4 +37,8 @@
         "android.hardware.cas.native@1.0",
         "android.hidl.memory@1.0",
     ],
+
+    whole_static_libs: [
+        "libstagefright_metadatautils",
+    ],
 }
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index b621fd0..850face 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -29,6 +29,7 @@
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
+#include <media/stagefright/MetaDataUtils.h>
 #include <media/cas/DescramblerAPI.h>
 #include <media/hardware/CryptoAPI.h>
 
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index ca691f7..4a36681 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -71,6 +71,7 @@
         "libmedia_omx",
         "libmedia_jni",
         "libmediadrm",
+        "libmediaextractor",
         "libstagefright",
         "libstagefright_foundation",
         "liblog",
diff --git a/packages/MediaComponents/res/layout/media_controller.xml b/packages/MediaComponents/res/layout/media_controller.xml
index 74a8306..dd56e7c 100644
--- a/packages/MediaComponents/res/layout/media_controller.xml
+++ b/packages/MediaComponents/res/layout/media_controller.xml
@@ -51,6 +51,7 @@
         <view class="com.android.support.mediarouter.app.MediaRouteButton" android:id="@+id/cast"
             android:layout_alignParentEnd="true"
             android:layout_centerVertical="true"
+            android:visibility="gone"
             style="@style/TitleBarButton" />
 
     </RelativeLayout>
diff --git a/packages/MediaComponents/res/values/attrs.xml b/packages/MediaComponents/res/values/attrs.xml
index 6175b11..e37285b 100644
--- a/packages/MediaComponents/res/values/attrs.xml
+++ b/packages/MediaComponents/res/values/attrs.xml
@@ -41,5 +41,4 @@
     <attr name="mediaRouteControlPanelThemeOverlay" format="reference" />
 
     <attr name="mediaRouteTheme" format="reference" />
-    <attr name="enableControlView" format="boolean" />
 </resources>
diff --git a/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java b/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java
index d21edae..3e6d98f 100644
--- a/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java
@@ -44,7 +44,7 @@
     }
 
     @Override
-    public void getBrowserRoot_impl(Bundle rootHints) {
+    public void getLibraryRoot_impl(Bundle rootHints) {
         final IMediaSession2 binder = getSessionBinder();
         if (binder != null) {
             try {
diff --git a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java b/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
index 4144342..41dfd00 100644
--- a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
@@ -43,6 +43,8 @@
 import android.support.annotation.GuardedBy;
 import android.util.Log;
 
+import com.android.media.MediaSession2Impl.CommandButtonImpl;
+
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
@@ -225,7 +227,7 @@
 
     @Override
     public void play_impl() {
-        sendTransportControlCommand(MediaSession2.COMMAND_CODE_PLAYBACK_START);
+        sendTransportControlCommand(MediaSession2.COMMAND_CODE_PLAYBACK_PLAY);
     }
 
     @Override
@@ -568,7 +570,8 @@
                 Log.w(TAG, "Don't fail silently here. Highly likely a bug");
                 return;
             }
-            controller.pushPlaybackStateChanges(PlaybackState2.fromBundle(state));
+            controller.pushPlaybackStateChanges(
+                    PlaybackState2.fromBundle(controller.getContext(), state));
         }
 
         @Override
@@ -595,7 +598,8 @@
                 Log.w(TAG, "Don't fail silently here. Highly likely a bug");
                 return;
             }
-            controller.pushPlaylistParamsChanges(PlaylistParams.fromBundle(params));
+            controller.pushPlaylistParamsChanges(
+                    PlaylistParams.fromBundle(controller.getContext(), params));
         }
 
         @Override
@@ -648,7 +652,7 @@
             }
             List<CommandButton> layout = new ArrayList<>();
             for (int i = 0; i < commandButtonlist.size(); i++) {
-                CommandButton button = CommandButton.fromBundle(
+                CommandButton button = CommandButtonImpl.fromBundle(
                         browser.getContext(), commandButtonlist.get(i));
                 if (button != null) {
                     layout.add(button);
diff --git a/packages/MediaComponents/src/com/android/media/MediaItem2Impl.java b/packages/MediaComponents/src/com/android/media/MediaItem2Impl.java
index 5639346..f51e246 100644
--- a/packages/MediaComponents/src/com/android/media/MediaItem2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaItem2Impl.java
@@ -90,7 +90,7 @@
         bundle.putString(KEY_ID, mId);
         bundle.putInt(KEY_FLAGS, mFlags);
         if (mMetadata != null) {
-            bundle.putBundle(KEY_METADATA, mMetadata.getBundle());
+            bundle.putBundle(KEY_METADATA, mMetadata.toBundle());
         }
         return bundle;
     }
@@ -102,7 +102,7 @@
         final String id = bundle.getString(KEY_ID);
         final Bundle metadataBundle = bundle.getBundle(KEY_METADATA);
         final MediaMetadata2 metadata = metadataBundle != null
-                ? new MediaMetadata2(metadataBundle) : null;
+                ? MediaMetadata2.fromBundle(context, metadataBundle) : null;
         final int flags = bundle.getInt(KEY_FLAGS);
         return new MediaItem2Impl(context, id, metadata, flags).getInstance();
     }
diff --git a/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java b/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
index 4b1b9de..54c8d41 100644
--- a/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
@@ -19,7 +19,9 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.media.MediaLibraryService2;
+import android.media.MediaLibraryService2.LibraryRoot;
 import android.media.MediaLibraryService2.MediaLibrarySession;
+import android.media.MediaLibraryService2.MediaLibrarySessionBuilder;
 import android.media.MediaLibraryService2.MediaLibrarySessionCallback;
 import android.media.MediaPlayerInterface;
 import android.media.MediaSession2;
@@ -30,6 +32,8 @@
 import android.media.update.MediaLibraryService2Provider;
 import android.os.Bundle;
 
+import com.android.media.MediaSession2Impl.BuilderBaseImpl;
+
 import java.util.concurrent.Executor;
 
 public class MediaLibraryService2Impl extends MediaSessionService2Impl implements
@@ -61,20 +65,28 @@
 
     public static class MediaLibrarySessionImpl extends MediaSession2Impl
             implements MediaLibrarySessionProvider {
-        private final MediaLibrarySession mInstance;
         private final MediaLibrarySessionCallback mCallback;
 
-        public MediaLibrarySessionImpl(Context context, MediaLibrarySession instance,
+        public MediaLibrarySessionImpl(Context context,
                 MediaPlayerInterface player, String id, VolumeProvider volumeProvider,
                 int ratingType, PendingIntent sessionActivity, Executor callbackExecutor,
-                MediaLibrarySessionCallback callback)  {
-            super(context, instance, player, id, volumeProvider, ratingType, sessionActivity,
+                MediaLibrarySessionCallback callback) {
+            super(context, player, id, volumeProvider, ratingType, sessionActivity,
                     callbackExecutor, callback);
-            mInstance = instance;
             mCallback = callback;
         }
 
         @Override
+        MediaLibrarySession createInstance() {
+            return new MediaLibrarySession(this);
+        }
+
+        @Override
+        MediaLibrarySession getInstance() {
+            return (MediaLibrarySession) super.getInstance();
+        }
+
+        @Override
         public void notifyChildrenChanged_impl(ControllerInfo controller, String parentId,
                 Bundle options) {
             // TODO(jaewan): Implements
@@ -85,4 +97,47 @@
             // TODO(jaewan): Implements
         }
     }
-}
+
+    public static class BuilderImpl
+            extends BuilderBaseImpl<MediaLibrarySession, MediaLibrarySessionCallback> {
+        public BuilderImpl(Context context, MediaLibrarySessionBuilder instance,
+                MediaPlayerInterface player, Executor callbackExecutor,
+                MediaLibrarySessionCallback callback) {
+            super(context, player);
+            setSessionCallback_impl(callbackExecutor, callback);
+        }
+
+        @Override
+        public MediaLibrarySession build_impl() {
+            return new MediaLibrarySessionImpl(mContext, mPlayer, mId, mVolumeProvider, mRatingType,
+                    mSessionActivity, mCallbackExecutor, mCallback).getInstance();
+        }
+    }
+
+    public static final class LibraryRootImpl implements LibraryRootProvider {
+        private final LibraryRoot mInstance;
+        private final String mRootId;
+        private final Bundle mExtras;
+
+        public LibraryRootImpl(Context context, LibraryRoot instance, String rootId,
+                Bundle extras) {
+            if (rootId == null) {
+                throw new IllegalArgumentException("The root id in BrowserRoot cannot be null. " +
+                        "Use null for BrowserRoot instead.");
+            }
+            mInstance = instance;
+            mRootId = rootId;
+            mExtras = extras;
+        }
+
+        @Override
+        public String getRootId_impl() {
+            return mRootId;
+        }
+
+        @Override
+        public Bundle getExtras_impl() {
+            return mExtras;
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/MediaComponents/src/com/android/media/MediaMetadata2Impl.java b/packages/MediaComponents/src/com/android/media/MediaMetadata2Impl.java
new file mode 100644
index 0000000..9088029
--- /dev/null
+++ b/packages/MediaComponents/src/com/android/media/MediaMetadata2Impl.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright 2018 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.
+ */
+
+package com.android.media;
+
+import static android.media.MediaMetadata2.*;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.media.MediaMetadata2;
+import android.media.MediaMetadata2.BitmapKey;
+import android.media.MediaMetadata2.Builder;
+import android.media.MediaMetadata2.LongKey;
+import android.media.MediaMetadata2.RatingKey;
+import android.media.MediaMetadata2.TextKey;
+import android.media.Rating2;
+import android.media.update.MediaMetadata2Provider;
+import android.os.Bundle;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import java.util.Set;
+
+public class MediaMetadata2Impl implements MediaMetadata2Provider {
+    private static final String TAG = "MediaMetadata2";
+
+    /**
+     * A {@link Bundle} extra.
+     * @hide
+     */
+    public static final String METADATA_KEY_EXTRA = "android.media.metadata.EXTRA";
+
+    static final int METADATA_TYPE_LONG = 0;
+    static final int METADATA_TYPE_TEXT = 1;
+    static final int METADATA_TYPE_BITMAP = 2;
+    static final int METADATA_TYPE_RATING = 3;
+    static final ArrayMap<String, Integer> METADATA_KEYS_TYPE;
+
+    static {
+        METADATA_KEYS_TYPE = new ArrayMap<String, Integer>();
+        METADATA_KEYS_TYPE.put(METADATA_KEY_TITLE, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_ARTIST, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_DURATION, METADATA_TYPE_LONG);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_AUTHOR, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_WRITER, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_COMPOSER, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_COMPILATION, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_DATE, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_YEAR, METADATA_TYPE_LONG);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_GENRE, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_TRACK_NUMBER, METADATA_TYPE_LONG);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_NUM_TRACKS, METADATA_TYPE_LONG);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_DISC_NUMBER, METADATA_TYPE_LONG);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ARTIST, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_ART, METADATA_TYPE_BITMAP);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_ART_URI, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ART, METADATA_TYPE_BITMAP);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ART_URI, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_USER_RATING, METADATA_TYPE_RATING);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_RATING, METADATA_TYPE_RATING);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_TITLE, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_SUBTITLE, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_DESCRIPTION, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_ICON, METADATA_TYPE_BITMAP);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_ICON_URI, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_MEDIA_ID, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_BT_FOLDER_TYPE, METADATA_TYPE_LONG);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_MEDIA_URI, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_ADVERTISEMENT, METADATA_TYPE_LONG);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_DOWNLOAD_STATUS, METADATA_TYPE_LONG);
+    }
+
+    private static final @TextKey
+    String[] PREFERRED_DESCRIPTION_ORDER = {
+            METADATA_KEY_TITLE,
+            METADATA_KEY_ARTIST,
+            METADATA_KEY_ALBUM,
+            METADATA_KEY_ALBUM_ARTIST,
+            METADATA_KEY_WRITER,
+            METADATA_KEY_AUTHOR,
+            METADATA_KEY_COMPOSER
+    };
+
+    private static final @BitmapKey
+    String[] PREFERRED_BITMAP_ORDER = {
+            METADATA_KEY_DISPLAY_ICON,
+            METADATA_KEY_ART,
+            METADATA_KEY_ALBUM_ART
+    };
+
+    private static final @TextKey
+    String[] PREFERRED_URI_ORDER = {
+            METADATA_KEY_DISPLAY_ICON_URI,
+            METADATA_KEY_ART_URI,
+            METADATA_KEY_ALBUM_ART_URI
+    };
+
+    private final Context mContext;
+    private final MediaMetadata2 mInstance;
+    private final Bundle mBundle;
+
+    public MediaMetadata2Impl(Context context, Bundle bundle) {
+        mContext = context;
+        mInstance = new MediaMetadata2(this);
+        mBundle = bundle;
+    }
+
+    public MediaMetadata2 getInstance() {
+        return mInstance;
+    }
+
+    @Override
+    public boolean containsKey_impl(String key) {
+        return mBundle.containsKey(key);
+    }
+
+    @Override
+    public CharSequence getText_impl(@TextKey String key) {
+        return mBundle.getCharSequence(key);
+    }
+
+    @Override
+    public @Nullable String getMediaId_impl() {
+        return mInstance.getString(METADATA_KEY_MEDIA_ID);
+    }
+
+    @Override
+    public String getString_impl(@TextKey String key) {
+        CharSequence text = mBundle.getCharSequence(key);
+        if (text != null) {
+            return text.toString();
+        }
+        return null;
+    }
+
+    @Override
+    public long getLong_impl(@LongKey String key) {
+        return mBundle.getLong(key, 0);
+    }
+
+    @Override
+    public Rating2 getRating_impl(@RatingKey String key) {
+        // TODO(jaewan): Add backward compatibility
+        Rating2 rating = null;
+        try {
+            rating = Rating2.fromBundle(mContext, mBundle.getBundle(key));
+        } catch (Exception e) {
+            // ignore, value was not a rating
+            Log.w(TAG, "Failed to retrieve a key as Rating.", e);
+        }
+        return rating;
+    }
+
+    @Override
+    public Bitmap getBitmap_impl(@BitmapKey String key) {
+        Bitmap bmp = null;
+        try {
+            bmp = mBundle.getParcelable(key);
+        } catch (Exception e) {
+            // ignore, value was not a bitmap
+            Log.w(TAG, "Failed to retrieve a key as Bitmap.", e);
+        }
+        return bmp;
+    }
+
+    @Override
+    public Bundle getExtra_impl() {
+        try {
+            return mBundle.getBundle(METADATA_KEY_EXTRA);
+        } catch (Exception e) {
+            // ignore, value was not an bundle
+            Log.w(TAG, "Failed to retrieve an extra");
+        }
+        return null;
+    }
+
+    @Override
+    public int size_impl() {
+        return mBundle.size();
+    }
+
+    @Override
+    public Set<String> keySet_impl() {
+        return mBundle.keySet();
+    }
+
+    @Override
+    public Bundle toBundle_impl() {
+        return mBundle;
+    }
+
+    public static MediaMetadata2 fromBundle(Context context, Bundle bundle) {
+        return new MediaMetadata2Impl(context, bundle).getInstance();
+    }
+
+    public static final class BuilderImpl implements MediaMetadata2Provider.BuilderProvider {
+        private final Context mContext;
+        private final MediaMetadata2.Builder mInstance;
+        private final Bundle mBundle;
+
+        public BuilderImpl(Context context, MediaMetadata2.Builder instance) {
+            mContext = context;
+            mInstance = instance;
+            mBundle = new Bundle();
+        }
+
+        public BuilderImpl(Context context, MediaMetadata2.Builder instance, MediaMetadata2 source) {
+            if (source == null) {
+                throw new IllegalArgumentException("source shouldn't be null");
+            }
+            mContext = context;
+            mInstance = instance;
+            mBundle = new Bundle(source.toBundle());
+        }
+
+        public BuilderImpl(Context context, int maxBitmapSize) {
+            mContext = context;
+            mInstance = new MediaMetadata2.Builder(this);
+            mBundle = new Bundle();
+
+            for (String key : mBundle.keySet()) {
+                Object value = mBundle.get(key);
+                if (value instanceof Bitmap) {
+                    Bitmap bmp = (Bitmap) value;
+                    if (bmp.getHeight() > maxBitmapSize || bmp.getWidth() > maxBitmapSize) {
+                        mInstance.putBitmap(key, scaleBitmap(bmp, maxBitmapSize));
+                    }
+                }
+            }
+        }
+
+        @Override
+        public Builder putText_impl(@TextKey String key, CharSequence value) {
+            if (METADATA_KEYS_TYPE.containsKey(key)) {
+                if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_TEXT) {
+                    throw new IllegalArgumentException("The " + key
+                            + " key cannot be used to put a CharSequence");
+                }
+            }
+            mBundle.putCharSequence(key, value);
+            return mInstance;
+        }
+
+        @Override
+        public Builder putString_impl(@TextKey String key, String value) {
+            if (METADATA_KEYS_TYPE.containsKey(key)) {
+                if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_TEXT) {
+                    throw new IllegalArgumentException("The " + key
+                            + " key cannot be used to put a String");
+                }
+            }
+            mBundle.putCharSequence(key, value);
+            return mInstance;
+        }
+
+        @Override
+        public Builder putLong_impl(@LongKey String key, long value) {
+            if (METADATA_KEYS_TYPE.containsKey(key)) {
+                if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_LONG) {
+                    throw new IllegalArgumentException("The " + key
+                            + " key cannot be used to put a long");
+                }
+            }
+            mBundle.putLong(key, value);
+            return mInstance;
+        }
+
+        @Override
+        public Builder putRating_impl(@RatingKey String key, Rating2 value) {
+            if (METADATA_KEYS_TYPE.containsKey(key)) {
+                if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_RATING) {
+                    throw new IllegalArgumentException("The " + key
+                            + " key cannot be used to put a Rating");
+                }
+            }
+            mBundle.putBundle(key, value.toBundle());
+            return mInstance;
+        }
+
+        @Override
+        public Builder putBitmap_impl(@BitmapKey String key, Bitmap value) {
+            if (METADATA_KEYS_TYPE.containsKey(key)) {
+                if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_BITMAP) {
+                    throw new IllegalArgumentException("The " + key
+                            + " key cannot be used to put a Bitmap");
+                }
+            }
+            mBundle.putParcelable(key, value);
+            return mInstance;
+        }
+
+        @Override
+        public Builder setExtra_impl(Bundle bundle) {
+            mBundle.putBundle(METADATA_KEY_EXTRA, bundle);
+            return mInstance;
+        }
+
+        @Override
+        public MediaMetadata2 build_impl() {
+            return new MediaMetadata2Impl(mContext, mBundle).getInstance();
+        }
+
+        private Bitmap scaleBitmap(Bitmap bmp, int maxSize) { float maxSizeF = maxSize;
+            float widthScale = maxSizeF / bmp.getWidth();
+            float heightScale = maxSizeF / bmp.getHeight();
+            float scale = Math.min(widthScale, heightScale);
+            int height = (int) (bmp.getHeight() * scale);
+            int width = (int) (bmp.getWidth() * scale);
+            return Bitmap.createScaledBitmap(bmp, width, height, true);
+        }
+    }
+}
+
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java b/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
index 53b35cc..f820cdc 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
@@ -16,6 +16,7 @@
 
 package com.android.media;
 
+import static android.media.MediaSession2.COMMAND_CODE_CUSTOM;
 import static android.media.SessionToken2.TYPE_LIBRARY_SERVICE;
 import static android.media.SessionToken2.TYPE_SESSION;
 import static android.media.SessionToken2.TYPE_SESSION_SERVICE;
@@ -31,6 +32,7 @@
 import android.content.pm.ResolveInfo;
 import android.media.MediaItem2;
 import android.media.MediaLibraryService2;
+import android.media.MediaMetadata2;
 import android.media.MediaPlayerInterface;
 import android.media.MediaPlayerInterface.PlaybackListener;
 import android.media.MediaSession2;
@@ -40,6 +42,8 @@
 import android.media.MediaSession2.CommandGroup;
 import android.media.MediaSession2.ControllerInfo;
 import android.media.MediaSession2.PlaylistParams;
+import android.media.MediaSession2.PlaylistParams.RepeatMode;
+import android.media.MediaSession2.PlaylistParams.ShuffleMode;
 import android.media.MediaSession2.SessionCallback;
 import android.media.MediaSessionService2;
 import android.media.PlaybackState2;
@@ -47,6 +51,7 @@
 import android.media.VolumeProvider;
 import android.media.session.MediaSessionManager;
 import android.media.update.MediaSession2Provider;
+import android.media.update.MediaSession2Provider.CommandButtonProvider;
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.os.Process;
@@ -98,11 +103,11 @@
      * @param ratingType
      * @param sessionActivity
      */
-    public MediaSession2Impl(Context context, MediaSession2 instance, MediaPlayerInterface player,
+    public MediaSession2Impl(Context context, MediaPlayerInterface player,
             String id, VolumeProvider volumeProvider, int ratingType, PendingIntent sessionActivity,
             Executor callbackExecutor, SessionCallback callback) {
-        mInstance = instance;
         // TODO(jaewan): Keep other params.
+        mInstance = createInstance();
 
         // Argument checks are done by builder already.
         // Initialize finals first.
@@ -110,8 +115,6 @@
         mId = id;
         mCallback = callback;
         mCallbackExecutor = callbackExecutor;
-        // Only remember player. Actual settings will be done in the initialize().
-        mPlayer = player;
         mSessionStub = new MediaSession2Stub(this);
 
         // Infer type from the id and package name.
@@ -130,6 +133,24 @@
             mSessionToken = new SessionToken2Impl(context, Process.myUid(), TYPE_SESSION,
                     mContext.getPackageName(), null, id, mSessionStub).getInstance();
         }
+
+        setPlayerLocked(player);
+
+        // Ask server for the sanity check, and starts
+        // Sanity check for making session ID unique 'per package' cannot be done in here.
+        // Server can only know if the package has another process and has another session with the
+        // same id. Note that 'ID is unique per package' is important for controller to distinguish
+        // a session in another package.
+        MediaSessionManager manager =
+                (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
+        if (!manager.onSessionCreated(mSessionToken)) {
+            throw new IllegalStateException("Session with the same id is already used by"
+                    + " another process. Use MediaController2 instead.");
+        }
+    }
+
+    MediaSession2 createInstance() {
+        return new MediaSession2(this);
     }
 
     private static String getServiceName(Context context, String serviceAction, String id) {
@@ -157,24 +178,6 @@
         return serviceName;
     }
 
-    @Override
-    public void initialize() {
-        synchronized (mLock) {
-            setPlayerLocked(mPlayer);
-        }
-        // Ask server for the sanity check, and starts
-        // Sanity check for making session ID unique 'per package' cannot be done in here.
-        // Server can only know if the package has another process and has another session with the
-        // same id. Note that 'ID is unique per package' is important for controller to distinguish
-        // a session in another package.
-        MediaSessionManager manager =
-                (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
-        if (!manager.onSessionCreated(mSessionToken)) {
-            throw new IllegalStateException("Session with the same id is already used by"
-                    + " another process. Use MediaController2 instead.");
-        }
-    }
-
     // TODO(jaewan): Add explicit release() and do not remove session object with the
     //               setPlayer(null). Token can be available when player is null, and
     //               controller can also attach to session.
@@ -549,7 +552,7 @@
                 throw new IllegalArgumentException("action shouldn't be null");
             }
             mInstance = instance;
-            mCommandCode = MediaSession2.COMMAND_CODE_CUSTOM;
+            mCommandCode = COMMAND_CODE_CUSTOM;
             mCustomCommand = action;
             mExtra = extra;
         }
@@ -582,7 +585,7 @@
          */
         public static Command fromBundle_impl(Context context, Bundle command) {
             int code = command.getInt(KEY_COMMAND_CODE);
-            if (code != MediaSession2.COMMAND_CODE_CUSTOM) {
+            if (code != COMMAND_CODE_CUSTOM) {
                 return new Command(context, code);
             } else {
                 String customCommand = command.getString(KEY_COMMAND_CUSTOM_COMMAND);
@@ -638,20 +641,10 @@
 
         @Override
         public void addAllPredefinedCommands_impl() {
-            // TODO(jaewan): Is there any better way than this?
-            mCommands.add(new Command(mContext, MediaSession2.COMMAND_CODE_PLAYBACK_START));
-            mCommands.add(new Command(mContext, MediaSession2.COMMAND_CODE_PLAYBACK_PAUSE));
-            mCommands.add(new Command(mContext, MediaSession2.COMMAND_CODE_PLAYBACK_STOP));
-            mCommands.add(new Command(mContext,
-                    MediaSession2.COMMAND_CODE_PLAYBACK_SKIP_NEXT_ITEM));
-            mCommands.add(new Command(mContext,
-                    MediaSession2.COMMAND_CODE_PLAYBACK_SKIP_PREV_ITEM));
-            mCommands.add(new Command(mContext, MediaSession2.COMMAND_CODE_PLAYBACK_PREPARE));
-            mCommands.add(new Command(mContext, MediaSession2.COMMAND_CODE_PLAYBACK_FAST_FORWARD));
-            mCommands.add(new Command(mContext, MediaSession2.COMMAND_CODE_PLAYBACK_REWIND));
-            mCommands.add(new Command(mContext, MediaSession2.COMMAND_CODE_PLAYBACK_SEEK_TO));
-            mCommands.add(new Command(mContext,
-                    MediaSession2.COMMAND_CODE_PLAYBACK_SET_CURRENT_PLAYLIST_ITEM));
+            final int COMMAND_CODE_MAX = 22;
+            for (int i = 1; i <= COMMAND_CODE_MAX; i++) {
+                mCommands.add(new Command(mContext, i));
+            }
         }
 
         @Override
@@ -666,7 +659,7 @@
 
         @Override
         public boolean hasCommand_impl(int code) {
-            if (code == MediaSession2.COMMAND_CODE_CUSTOM) {
+            if (code == COMMAND_CODE_CUSTOM) {
                 throw new IllegalArgumentException("Use hasCommand(Command) for custom command");
             }
             for (int i = 0; i < mCommands.size(); i++) {
@@ -814,4 +807,306 @@
             return (ControllerInfoImpl) controller.getProvider();
         }
     }
+
+    public static class PlaylistParamsImpl implements PlaylistParamsProvider {
+        /**
+         * Keys used for converting a PlaylistParams object to a bundle object and vice versa.
+         */
+        private static final String KEY_REPEAT_MODE =
+                "android.media.session2.playlistparams2.repeat_mode";
+        private static final String KEY_SHUFFLE_MODE =
+                "android.media.session2.playlistparams2.shuffle_mode";
+        private static final String KEY_MEDIA_METADATA2_BUNDLE =
+                "android.media.session2.playlistparams2.metadata2_bundle";
+
+        private Context mContext;
+        private PlaylistParams mInstance;
+        private @RepeatMode int mRepeatMode;
+        private @ShuffleMode int mShuffleMode;
+        private MediaMetadata2 mPlaylistMetadata;
+
+        public PlaylistParamsImpl(Context context, PlaylistParams instance,
+                @RepeatMode int repeatMode, @ShuffleMode int shuffleMode,
+                MediaMetadata2 playlistMetadata) {
+            // TODO(jaewan): Sanity check
+            mContext = context;
+            mInstance = instance;
+            mRepeatMode = repeatMode;
+            mShuffleMode = shuffleMode;
+            mPlaylistMetadata = playlistMetadata;
+        }
+
+        public @RepeatMode int getRepeatMode_impl() {
+            return mRepeatMode;
+        }
+
+        public @ShuffleMode int getShuffleMode_impl() {
+            return mShuffleMode;
+        }
+
+        public MediaMetadata2 getPlaylistMetadata_impl() {
+            return mPlaylistMetadata;
+        }
+
+        @Override
+        public Bundle toBundle_impl() {
+            Bundle bundle = new Bundle();
+            bundle.putInt(KEY_REPEAT_MODE, mRepeatMode);
+            bundle.putInt(KEY_SHUFFLE_MODE, mShuffleMode);
+            if (mPlaylistMetadata != null) {
+                bundle.putBundle(KEY_MEDIA_METADATA2_BUNDLE, mPlaylistMetadata.toBundle());
+            }
+            return bundle;
+        }
+
+        public static PlaylistParams fromBundle(Context context, Bundle bundle) {
+            if (bundle == null) {
+                return null;
+            }
+            if (!bundle.containsKey(KEY_REPEAT_MODE) || !bundle.containsKey(KEY_SHUFFLE_MODE)) {
+                return null;
+            }
+
+            Bundle metadataBundle = bundle.getBundle(KEY_MEDIA_METADATA2_BUNDLE);
+            MediaMetadata2 metadata = metadataBundle == null
+                    ? null : MediaMetadata2.fromBundle(context, metadataBundle);
+
+            return new PlaylistParams(context,
+                    bundle.getInt(KEY_REPEAT_MODE),
+                    bundle.getInt(KEY_SHUFFLE_MODE),
+                    metadata);
+        }
+    }
+
+    public static class CommandButtonImpl implements CommandButtonProvider {
+        private static final String KEY_COMMAND
+                = "android.media.media_session2.command_button.command";
+        private static final String KEY_ICON_RES_ID
+                = "android.media.media_session2.command_button.icon_res_id";
+        private static final String KEY_DISPLAY_NAME
+                = "android.media.media_session2.command_button.display_name";
+        private static final String KEY_EXTRA
+                = "android.media.media_session2.command_button.extra";
+        private static final String KEY_ENABLED
+                = "android.media.media_session2.command_button.enabled";
+
+        private final CommandButton mInstance;
+        private Command mCommand;
+        private int mIconResId;
+        private String mDisplayName;
+        private Bundle mExtra;
+        private boolean mEnabled;
+
+        public CommandButtonImpl(Context context, @Nullable Command command, int iconResId,
+                @Nullable String displayName, Bundle extra, boolean enabled) {
+            mCommand = command;
+            mIconResId = iconResId;
+            mDisplayName = displayName;
+            mExtra = extra;
+            mEnabled = enabled;
+            mInstance = new CommandButton(this);
+        }
+
+        @Override
+        public @Nullable Command getCommand_impl() {
+            return mCommand;
+        }
+
+        @Override
+        public int getIconResId_impl() {
+            return mIconResId;
+        }
+
+        @Override
+        public @Nullable String getDisplayName_impl() {
+            return mDisplayName;
+        }
+
+        @Override
+        public @Nullable Bundle getExtra_impl() {
+            return mExtra;
+        }
+
+        @Override
+        public boolean isEnabled_impl() {
+            return mEnabled;
+        }
+
+        public @NonNull Bundle toBundle() {
+            Bundle bundle = new Bundle();
+            bundle.putBundle(KEY_COMMAND, mCommand.toBundle());
+            bundle.putInt(KEY_ICON_RES_ID, mIconResId);
+            bundle.putString(KEY_DISPLAY_NAME, mDisplayName);
+            bundle.putBundle(KEY_EXTRA, mExtra);
+            bundle.putBoolean(KEY_ENABLED, mEnabled);
+            return bundle;
+        }
+
+        public static @Nullable CommandButton fromBundle(Context context, Bundle bundle) {
+            if (bundle == null) {
+                return null;
+            }
+            CommandButton.Builder builder = new CommandButton.Builder(context);
+            builder.setCommand(Command.fromBundle(context, bundle.getBundle(KEY_COMMAND)));
+            builder.setIconResId(bundle.getInt(KEY_ICON_RES_ID, 0));
+            builder.setDisplayName(bundle.getString(KEY_DISPLAY_NAME));
+            builder.setExtra(bundle.getBundle(KEY_EXTRA));
+            builder.setEnabled(bundle.getBoolean(KEY_ENABLED));
+            try {
+                return builder.build();
+            } catch (IllegalStateException e) {
+                // Malformed or version mismatch. Return null for now.
+                return null;
+            }
+        }
+
+        /**
+         * Builder for {@link CommandButton}.
+         */
+        public static class BuilderImpl implements CommandButtonProvider.BuilderProvider {
+            private final Context mContext;
+            private final CommandButton.Builder mInstance;
+            private Command mCommand;
+            private int mIconResId;
+            private String mDisplayName;
+            private Bundle mExtra;
+            private boolean mEnabled;
+
+            public BuilderImpl(Context context, CommandButton.Builder instance) {
+                mContext = context;
+                mInstance = instance;
+                mEnabled = true;
+            }
+
+            @Override
+            public CommandButton.Builder setCommand_impl(Command command) {
+                mCommand = command;
+                return mInstance;
+            }
+
+            @Override
+            public CommandButton.Builder setIconResId_impl(int resId) {
+                mIconResId = resId;
+                return mInstance;
+            }
+
+            @Override
+            public CommandButton.Builder setDisplayName_impl(String displayName) {
+                mDisplayName = displayName;
+                return mInstance;
+            }
+
+            @Override
+            public CommandButton.Builder setEnabled_impl(boolean enabled) {
+                mEnabled = enabled;
+                return mInstance;
+            }
+
+            @Override
+            public CommandButton.Builder setExtra_impl(Bundle extra) {
+                mExtra = extra;
+                return mInstance;
+            }
+
+            @Override
+            public CommandButton build_impl() {
+                if (mEnabled && mCommand == null) {
+                    throw new IllegalStateException("Enabled button needs Command"
+                            + " for controller to invoke the command");
+                }
+                if (mCommand != null && mCommand.getCommandCode() == COMMAND_CODE_CUSTOM
+                        && (mIconResId == 0 || TextUtils.isEmpty(mDisplayName))) {
+                    throw new IllegalStateException("Custom commands needs icon and"
+                            + " and name to display");
+                }
+                return new CommandButtonImpl(
+                        mContext, mCommand, mIconResId, mDisplayName, mExtra, mEnabled).mInstance;
+            }
+        }
+    }
+
+    public static abstract class BuilderBaseImpl<T extends MediaSession2, C extends SessionCallback>
+            implements BuilderBaseProvider<T, C> {
+        final Context mContext;
+        final MediaPlayerInterface mPlayer;
+        String mId;
+        Executor mCallbackExecutor;
+        C mCallback;
+        VolumeProvider mVolumeProvider;
+        int mRatingType;
+        PendingIntent mSessionActivity;
+
+        /**
+         * Constructor.
+         *
+         * @param context a context
+         * @param player a player to handle incoming command from any controller.
+         * @throws IllegalArgumentException if any parameter is null, or the player is a
+         *      {@link MediaSession2} or {@link MediaController2}.
+         */
+        // TODO(jaewan): Also need executor
+        public BuilderBaseImpl(Context context, MediaPlayerInterface player) {
+            if (context == null) {
+                throw new IllegalArgumentException("context shouldn't be null");
+            }
+            if (player == null) {
+                throw new IllegalArgumentException("player shouldn't be null");
+            }
+            mContext = context;
+            mPlayer = player;
+            // Ensure non-null
+            mId = "";
+        }
+
+        public void setVolumeProvider_impl(VolumeProvider volumeProvider) {
+            mVolumeProvider = volumeProvider;
+        }
+
+        public void setRatingType_impl(int type) {
+            mRatingType = type;
+        }
+
+        public void setSessionActivity_impl(PendingIntent pi) {
+            mSessionActivity = pi;
+        }
+
+        public void setId_impl(String id) {
+            if (id == null) {
+                throw new IllegalArgumentException("id shouldn't be null");
+            }
+            mId = id;
+        }
+
+        public void setSessionCallback_impl(Executor executor, C callback) {
+            if (executor == null) {
+                throw new IllegalArgumentException("executor shouldn't be null");
+            }
+            if (callback == null) {
+                throw new IllegalArgumentException("callback shouldn't be null");
+            }
+            mCallbackExecutor = executor;
+            mCallback = callback;
+        }
+
+        public abstract T build_impl();
+    }
+
+    public static class BuilderImpl extends BuilderBaseImpl<MediaSession2, SessionCallback> {
+        public BuilderImpl(Context context, Builder instance, MediaPlayerInterface player) {
+            super(context, player);
+        }
+
+        @Override
+        public MediaSession2 build_impl() {
+            if (mCallbackExecutor == null) {
+                mCallbackExecutor = mContext.getMainExecutor();
+            }
+            if (mCallback == null) {
+                mCallback = new SessionCallback(mContext);
+            }
+
+            return new MediaSession2Impl(mContext, mPlayer, mId, mVolumeProvider, mRatingType,
+                    mSessionActivity, mCallbackExecutor, mCallback).getInstance();
+        }
+    }
 }
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java b/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
index 4bb5f47..1f71187 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
@@ -18,7 +18,7 @@
 
 import android.content.Context;
 import android.media.MediaItem2;
-import android.media.MediaLibraryService2.BrowserRoot;
+import android.media.MediaLibraryService2.LibraryRoot;
 import android.media.MediaLibraryService2.MediaLibrarySessionCallback;
 import android.media.MediaSession2;
 import android.media.MediaSession2.Command;
@@ -27,6 +27,7 @@
 import android.media.MediaSession2.ControllerInfo;
 import android.media.MediaSession2.PlaylistParams;
 import android.media.PlaybackState2;
+import android.media.update.MediaSession2Provider.CommandButtonProvider;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -36,6 +37,7 @@
 import android.util.ArrayMap;
 import android.util.Log;
 
+import com.android.media.MediaSession2Impl.CommandButtonImpl;
 import com.android.media.MediaSession2Impl.ControllerInfoImpl;
 
 import java.lang.ref.WeakReference;
@@ -192,7 +194,7 @@
             }
 
             switch (commandCode) {
-                case MediaSession2.COMMAND_CODE_PLAYBACK_START:
+                case MediaSession2.COMMAND_CODE_PLAYBACK_PLAY:
                     session.getInstance().play();
                     break;
                 case MediaSession2.COMMAND_CODE_PLAYBACK_PAUSE:
@@ -225,7 +227,7 @@
                     break;
                 case MediaSession2.COMMAND_CODE_PLAYBACK_SET_PLAYLIST_PARAMS:
                     session.getInstance().setPlaylistParams(
-                            PlaylistParams.fromBundle(
+                            PlaylistParams.fromBundle(session.getContext(),
                                     args.getBundle(ARGUMENT_KEY_PLAYLIST_PARAMS)));
                     break;
                 default:
@@ -261,7 +263,7 @@
         final MediaSession2Impl sessionImpl = getSession();
         if (!(sessionImpl.getCallback() instanceof MediaLibrarySessionCallback)) {
             if (DEBUG) {
-                Log.d(TAG, "Session cannot hand getBrowserRoot()");
+                Log.d(TAG, "Session cannot hand getLibraryRoot()");
             }
             return;
         }
@@ -280,7 +282,7 @@
             final MediaLibrarySessionCallback libraryCallback =
                     (MediaLibrarySessionCallback) session.getCallback();
             final ControllerInfoImpl controllerImpl = ControllerInfoImpl.from(controller);
-            BrowserRoot root = libraryCallback.onGetRoot(controller, rootHints);
+            LibraryRoot root = libraryCallback.onGetRoot(controller, rootHints);
             try {
                 controllerImpl.getControllerBinder().onGetRootResult(rootHints,
                         root == null ? null : root.getRootId(),
@@ -336,7 +338,7 @@
         try {
             List<Bundle> layoutBundles = new ArrayList<>();
             for (int i = 0; i < layout.size(); i++) {
-                Bundle bundle = layout.get(i).toBundle();
+                Bundle bundle = ((CommandButtonImpl) layout.get(i).getProvider()).toBundle();
                 if (bundle != null) {
                     layoutBundles.add(bundle);
                 }
diff --git a/packages/MediaComponents/src/com/android/media/MediaSessionService2Impl.java b/packages/MediaComponents/src/com/android/media/MediaSessionService2Impl.java
index 7dce109..8773df4 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSessionService2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSessionService2Impl.java
@@ -18,7 +18,9 @@
 
 import static android.content.Context.NOTIFICATION_SERVICE;
 
+import android.app.Notification;
 import android.app.NotificationManager;
+import android.content.Context;
 import android.content.Intent;
 import android.media.MediaPlayerInterface.PlaybackListener;
 import android.media.MediaSession2;
@@ -116,7 +118,8 @@
                 if (!mIsRunningForeground) {
                     mIsRunningForeground = true;
                     mInstance.startForegroundService(mStartSelfIntent);
-                    mInstance.startForeground(mediaNotification.id, mediaNotification.notification);
+                    mInstance.startForeground(mediaNotification.getNotificationId(),
+                            mediaNotification.getNotification());
                     return;
                 }
                 break;
@@ -128,7 +131,8 @@
                 }
                 break;
         }
-        mNotificationManager.notify(mediaNotification.id, mediaNotification.notification);
+        mNotificationManager.notify(mediaNotification.getNotificationId(),
+                mediaNotification.getNotification());
     }
 
     private class SessionServicePlaybackListener implements PlaybackListener {
@@ -142,4 +146,28 @@
             updateNotification(state);
         }
     }
+
+    public static class MediaNotificationImpl implements MediaNotificationProvider {
+        private int mNotificationId;
+        private Notification mNotification;
+
+        public MediaNotificationImpl(Context context, MediaNotification instance,
+                int notificationId, Notification notification) {
+            if (notification == null) {
+                throw new IllegalArgumentException("notification shouldn't be null");
+            }
+            mNotificationId = notificationId;
+            mNotification = notification;
+        }
+
+        @Override
+        public int getNotificationId_impl() {
+            return mNotificationId;
+        }
+
+        @Override
+        public Notification getNotification_impl() {
+            return mNotification;
+        }
+    }
 }
diff --git a/packages/MediaComponents/src/com/android/media/PlaybackInfoImpl.java b/packages/MediaComponents/src/com/android/media/PlaybackInfoImpl.java
new file mode 100644
index 0000000..0782cf1
--- /dev/null
+++ b/packages/MediaComponents/src/com/android/media/PlaybackInfoImpl.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2018 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.
+ */
+
+package com.android.media;
+
+import android.content.Context;
+import android.media.AudioAttributes;
+import android.media.MediaController2.PlaybackInfo;
+import android.media.update.PlaybackInfoProvider;
+import android.os.Bundle;
+
+public final class PlaybackInfoImpl implements PlaybackInfoProvider {
+
+    private static final String KEY_PLAYBACK_TYPE =
+            "android.media.playbackinfo_impl.playback_type";
+    private static final String KEY_CONTROL_TYPE =
+            "android.media.playbackinfo_impl.control_type";
+    private static final String KEY_MAX_VOLUME =
+            "android.media.playbackinfo_impl.max_volume";
+    private static final String KEY_CURRENT_VOLUME =
+            "android.media.playbackinfo_impl.current_volume";
+    private static final String KEY_AUDIO_ATTRIBUTES =
+            "android.media.playbackinfo_impl.audio_attrs";
+
+    private final Context mContext;
+    private final PlaybackInfo mInstance;
+
+    private final int mPlaybackType;
+    private final int mControlType;
+    private final int mMaxVolume;
+    private final int mCurrentVolume;
+    private final AudioAttributes mAudioAttrs;
+
+    private PlaybackInfoImpl(Context context, int playbackType, AudioAttributes attrs,
+            int controlType, int max, int current) {
+        mContext = context;
+        mPlaybackType = playbackType;
+        mAudioAttrs = attrs;
+        mControlType = controlType;
+        mMaxVolume = max;
+        mCurrentVolume = current;
+        mInstance = new PlaybackInfo(this);
+    }
+
+    @Override
+    public int getPlaybackType_impl() {
+        return mPlaybackType;
+    }
+
+    @Override
+    public AudioAttributes getAudioAttributes_impl() {
+        return mAudioAttrs;
+    }
+
+    @Override
+    public int getControlType_impl() {
+        return mControlType;
+    }
+
+    @Override
+    public int getMaxVolume_impl() {
+        return mMaxVolume;
+    }
+
+    @Override
+    public int getCurrentVolume_impl() {
+        return mCurrentVolume;
+    }
+
+    public PlaybackInfo getInstance() {
+        return mInstance;
+    }
+
+    public Bundle toBundle() {
+        Bundle bundle = new Bundle();
+        bundle.putInt(KEY_PLAYBACK_TYPE, mPlaybackType);
+        bundle.putInt(KEY_CONTROL_TYPE, mControlType);
+        bundle.putInt(KEY_MAX_VOLUME, mMaxVolume);
+        bundle.putInt(KEY_CURRENT_VOLUME, mCurrentVolume);
+        bundle.putParcelable(KEY_AUDIO_ATTRIBUTES, mAudioAttrs);
+        return bundle;
+    }
+
+    public static PlaybackInfo createPlaybackInfo(Context context, int playbackType,
+            AudioAttributes attrs, int controlType, int max, int current) {
+        return new PlaybackInfoImpl(context, playbackType, attrs, controlType, max, current)
+                .getInstance();
+    }
+
+    public static PlaybackInfo fromBundle(Context context, Bundle bundle) {
+        if (bundle == null) {
+            return null;
+        }
+        final int volumeType = bundle.getInt(KEY_PLAYBACK_TYPE);
+        final int volumeControl = bundle.getInt(KEY_CONTROL_TYPE);
+        final int maxVolume = bundle.getInt(KEY_MAX_VOLUME);
+        final int currentVolume = bundle.getInt(KEY_CURRENT_VOLUME);
+        final AudioAttributes attrs = bundle.getParcelable(KEY_AUDIO_ATTRIBUTES);
+
+        return createPlaybackInfo(
+                context, volumeType, attrs, volumeControl, maxVolume, currentVolume);
+    }
+}
diff --git a/packages/MediaComponents/src/com/android/media/PlaybackState2Impl.java b/packages/MediaComponents/src/com/android/media/PlaybackState2Impl.java
new file mode 100644
index 0000000..5eb1129
--- /dev/null
+++ b/packages/MediaComponents/src/com/android/media/PlaybackState2Impl.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2018 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.
+ */
+
+package com.android.media;
+
+import android.content.Context;
+import android.media.PlaybackState2;
+import android.media.update.PlaybackState2Provider;
+import android.os.Bundle;
+
+public final class PlaybackState2Impl implements PlaybackState2Provider {
+    /**
+     * Keys used for converting a PlaybackState2 to a bundle object and vice versa.
+     */
+    private static final String KEY_STATE = "android.media.playbackstate2.state";
+    private static final String KEY_POSITION = "android.media.playbackstate2.position";
+    private static final String KEY_BUFFERED_POSITION =
+            "android.media.playbackstate2.buffered_position";
+    private static final String KEY_SPEED = "android.media.playbackstate2.speed";
+    private static final String KEY_ERROR_MESSAGE = "android.media.playbackstate2.error_message";
+    private static final String KEY_UPDATE_TIME = "android.media.playbackstate2.update_time";
+    private static final String KEY_ACTIVE_ITEM_ID = "android.media.playbackstate2.active_item_id";
+
+    private final Context mContext;
+    private final PlaybackState2 mInstance;
+    private final int mState;
+    private final long mPosition;
+    private final long mUpdateTime;
+    private final float mSpeed;
+    private final long mBufferedPosition;
+    private final long mActiveItemId;
+    private final CharSequence mErrorMessage;
+
+    public PlaybackState2Impl(Context context, PlaybackState2 instance, int state, long position,
+            long updateTime, float speed, long bufferedPosition, long activeItemId,
+            CharSequence error) {
+        mContext = context;
+        mInstance = instance;
+        mState = state;
+        mPosition = position;
+        mSpeed = speed;
+        mUpdateTime = updateTime;
+        mBufferedPosition = bufferedPosition;
+        mActiveItemId = activeItemId;
+        mErrorMessage = error;
+    }
+
+    @Override
+    public String toString_impl() {
+        StringBuilder bob = new StringBuilder("PlaybackState {");
+        bob.append("state=").append(mState);
+        bob.append(", position=").append(mPosition);
+        bob.append(", buffered position=").append(mBufferedPosition);
+        bob.append(", speed=").append(mSpeed);
+        bob.append(", updated=").append(mUpdateTime);
+        bob.append(", active item id=").append(mActiveItemId);
+        bob.append(", error=").append(mErrorMessage);
+        bob.append("}");
+        return bob.toString();
+    }
+
+    @Override
+    public int getState_impl() {
+        return mState;
+    }
+
+    @Override
+    public long getPosition_impl() {
+        return mPosition;
+    }
+
+    @Override
+    public long getBufferedPosition_impl() {
+        return mBufferedPosition;
+    }
+
+    @Override
+    public float getPlaybackSpeed_impl() {
+        return mSpeed;
+    }
+
+    @Override
+    public CharSequence getErrorMessage_impl() {
+        return mErrorMessage;
+    }
+
+    @Override
+    public long getLastPositionUpdateTime_impl() {
+        return mUpdateTime;
+    }
+
+    @Override
+    public long getCurrentPlaylistItemIndex_impl() {
+        return mActiveItemId;
+    }
+
+    @Override
+    public Bundle toBundle_impl() {
+        Bundle bundle = new Bundle();
+        bundle.putInt(KEY_STATE, mState);
+        bundle.putLong(KEY_POSITION, mPosition);
+        bundle.putLong(KEY_UPDATE_TIME, mUpdateTime);
+        bundle.putFloat(KEY_SPEED, mSpeed);
+        bundle.putLong(KEY_BUFFERED_POSITION, mBufferedPosition);
+        bundle.putLong(KEY_ACTIVE_ITEM_ID, mActiveItemId);
+        bundle.putCharSequence(KEY_ERROR_MESSAGE, mErrorMessage);
+        return bundle;
+    }
+
+    public static PlaybackState2 fromBundle(Context context, Bundle bundle) {
+        if (bundle == null) {
+            return null;
+        }
+        if (!bundle.containsKey(KEY_STATE)
+                || !bundle.containsKey(KEY_POSITION)
+                || !bundle.containsKey(KEY_UPDATE_TIME)
+                || !bundle.containsKey(KEY_SPEED)
+                || !bundle.containsKey(KEY_BUFFERED_POSITION)
+                || !bundle.containsKey(KEY_ACTIVE_ITEM_ID)
+                || !bundle.containsKey(KEY_ERROR_MESSAGE)) {
+            return null;
+        }
+
+        return new PlaybackState2(context,
+                bundle.getInt(KEY_STATE),
+                bundle.getLong(KEY_POSITION),
+                bundle.getLong(KEY_UPDATE_TIME),
+                bundle.getFloat(KEY_SPEED),
+                bundle.getLong(KEY_BUFFERED_POSITION),
+                bundle.getLong(KEY_ACTIVE_ITEM_ID),
+                bundle.getCharSequence(KEY_ERROR_MESSAGE));
+    }
+}
\ No newline at end of file
diff --git a/packages/MediaComponents/src/com/android/media/Rating2Impl.java b/packages/MediaComponents/src/com/android/media/Rating2Impl.java
new file mode 100644
index 0000000..68e104a
--- /dev/null
+++ b/packages/MediaComponents/src/com/android/media/Rating2Impl.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2018 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.
+ */
+
+package com.android.media;
+
+import static android.media.Rating2.*;
+
+import android.content.Context;
+import android.media.Rating2;
+import android.media.Rating2.Style;
+import android.media.update.Rating2Provider;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.util.Objects;
+
+public final class Rating2Impl implements Rating2Provider {
+    private static final String TAG = "Rating2";
+
+    private static final String KEY_STYLE = "android.media.rating2.style";
+    private static final String KEY_VALUE = "android.media.rating2.value";
+
+    private final static float RATING_NOT_RATED = -1.0f;
+
+    private final Rating2 mInstance;
+    private final int mRatingStyle;
+    private final float mRatingValue;
+
+    private Rating2Impl(Context context, @Style int ratingStyle, float rating) {
+        mRatingStyle = ratingStyle;
+        mRatingValue = rating;
+        mInstance = new Rating2(this);
+    }
+
+    @Override
+    public String toString_impl() {
+        return "Rating2:style=" + mRatingStyle + " rating="
+                + (mRatingValue < 0.0f ? "unrated" : String.valueOf(mRatingValue));
+    }
+
+    @Override
+    public boolean equals_impl(Object obj) {
+        if (!(obj instanceof Rating2)) {
+            return false;
+        }
+        Rating2Impl other = (Rating2Impl) ((Rating2) obj).getProvider();
+        return mRatingStyle == other.mRatingStyle
+                && mRatingValue == other.mRatingValue;
+    }
+
+    @Override
+    public int hashCode_impl() {
+        return Objects.hash(mRatingStyle, mRatingValue);
+    }
+
+    public Rating2 getInstance() {
+        return mInstance;
+    }
+
+    public static Rating2 fromBundle(Context context, Bundle bundle) {
+        if (bundle == null) {
+            return null;
+        }
+        return new Rating2Impl(context, bundle.getInt(KEY_STYLE), bundle.getFloat(KEY_VALUE))
+                .getInstance();
+    }
+
+    public Bundle toBundle_impl() {
+        Bundle bundle = new Bundle();
+        bundle.putInt(KEY_STYLE, mRatingStyle);
+        bundle.putFloat(KEY_VALUE, mRatingValue);
+        return bundle;
+    }
+
+    public static Rating2 newUnratedRating(Context context, @Style int ratingStyle) {
+        switch(ratingStyle) {
+            case RATING_HEART:
+            case RATING_THUMB_UP_DOWN:
+            case RATING_3_STARS:
+            case RATING_4_STARS:
+            case RATING_5_STARS:
+            case RATING_PERCENTAGE:
+                return new Rating2Impl(context, ratingStyle, RATING_NOT_RATED).getInstance();
+            default:
+                return null;
+        }
+    }
+
+    public static Rating2 newHeartRating(Context context, boolean hasHeart) {
+        return new Rating2Impl(context, RATING_HEART, hasHeart ? 1.0f : 0.0f).getInstance();
+    }
+
+    public static Rating2 newThumbRating(Context context, boolean thumbIsUp) {
+        return new Rating2Impl(context, RATING_THUMB_UP_DOWN, thumbIsUp ? 1.0f : 0.0f)
+                .getInstance();
+    }
+
+    public static Rating2 newStarRating(Context context, int starRatingStyle, float starRating) {
+        float maxRating = RATING_NOT_RATED;
+        switch(starRatingStyle) {
+            case RATING_3_STARS:
+                maxRating = 3.0f;
+                break;
+            case RATING_4_STARS:
+                maxRating = 4.0f;
+                break;
+            case RATING_5_STARS:
+                maxRating = 5.0f;
+                break;
+            default:
+                Log.e(TAG, "Invalid rating style (" + starRatingStyle + ") for a star rating");
+                return null;
+        }
+        if ((starRating < 0.0f) || (starRating > maxRating)) {
+            Log.e(TAG, "Trying to set out of range star-based rating");
+            return null;
+        }
+        return new Rating2Impl(context, starRatingStyle, starRating).getInstance();
+    }
+
+    public static Rating2 newPercentageRating(Context context, float percent) {
+        if ((percent < 0.0f) || (percent > 100.0f)) {
+            Log.e(TAG, "Invalid percentage-based rating value");
+            return null;
+        } else {
+            return new Rating2Impl(context, RATING_PERCENTAGE, percent).getInstance();
+        }
+    }
+
+    @Override
+    public boolean isRated_impl() {
+        return mRatingValue >= 0.0f;
+    }
+
+    @Override
+    public int getRatingStyle_impl() {
+        return mRatingStyle;
+    }
+
+    @Override
+    public boolean hasHeart_impl() {
+        if (mRatingStyle != RATING_HEART) {
+            return false;
+        } else {
+            return (mRatingValue == 1.0f);
+        }
+    }
+
+    @Override
+    public boolean isThumbUp_impl() {
+        if (mRatingStyle != RATING_THUMB_UP_DOWN) {
+            return false;
+        } else {
+            return (mRatingValue == 1.0f);
+        }
+    }
+
+    @Override
+    public float getStarRating_impl() {
+        switch (mRatingStyle) {
+            case RATING_3_STARS:
+            case RATING_4_STARS:
+            case RATING_5_STARS:
+                if (mInstance.isRated()) {
+                    return mRatingValue;
+                }
+            default:
+                return -1.0f;
+        }
+    }
+
+    @Override
+    public float getPercentRating_impl() {
+        if ((mRatingStyle != RATING_PERCENTAGE) || !mInstance.isRated()) {
+            return -1.0f;
+        } else {
+            return mRatingValue;
+        }
+    }
+}
diff --git a/packages/MediaComponents/src/com/android/media/VolumeProvider2Impl.java b/packages/MediaComponents/src/com/android/media/VolumeProvider2Impl.java
new file mode 100644
index 0000000..5af3ddf
--- /dev/null
+++ b/packages/MediaComponents/src/com/android/media/VolumeProvider2Impl.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2018 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.
+ */
+package com.android.media;
+
+import android.content.Context;
+import android.media.VolumeProvider2;
+import android.media.update.VolumeProvider2Provider;
+
+public class VolumeProvider2Impl implements VolumeProvider2Provider {
+
+    private final Context mContext;
+    private final VolumeProvider2 mInstance;
+    private final int mControlType;
+    private final int mMaxVolume;
+
+    private int mCurrentVolume;
+    private Callback mCallback;
+
+    public VolumeProvider2Impl(Context context, VolumeProvider2 instance,
+            @VolumeProvider2.ControlType int controlType, int maxVolume, int currentVolume) {
+        mContext = context;
+        mInstance = instance;
+        mControlType = controlType;
+        mMaxVolume = maxVolume;
+        mCurrentVolume = currentVolume;
+    }
+
+    @Override
+    public int getControlType_impl() {
+        return mControlType;
+    }
+
+    @Override
+    public int getMaxVolume_impl() {
+        return mMaxVolume;
+    }
+
+    @Override
+    public int getCurrentVolume_impl() {
+        return mCurrentVolume;
+    }
+
+    @Override
+    public void setCurrentVolume_impl(int currentVolume) {
+        mCurrentVolume = currentVolume;
+        if (mCallback != null) {
+            mCallback.onVolumeChanged(mInstance);
+        }
+    }
+
+    /**
+     * Sets a callback to receive volume changes.
+     */
+    public void setCallback(Callback callback) {
+        mCallback = callback;
+    }
+
+    /**
+     * Listens for changes to the volume.
+     */
+    public static abstract class Callback {
+        public abstract void onVolumeChanged(VolumeProvider2 volumeProvider);
+    }
+}
diff --git a/packages/MediaComponents/src/com/android/media/update/ApiFactory.java b/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
index 8fbbe5f..661e252 100644
--- a/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
+++ b/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
@@ -16,7 +16,7 @@
 
 package com.android.media.update;
 
-import android.app.PendingIntent;
+import android.app.Notification;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
@@ -27,31 +27,45 @@
 import android.media.MediaController2.ControllerCallback;
 import android.media.MediaItem2;
 import android.media.MediaLibraryService2;
+import android.media.MediaLibraryService2.LibraryRoot;
 import android.media.MediaLibraryService2.MediaLibrarySession;
+import android.media.MediaLibraryService2.MediaLibrarySessionBuilder;
 import android.media.MediaLibraryService2.MediaLibrarySessionCallback;
 import android.media.MediaMetadata2;
 import android.media.MediaPlayerInterface;
 import android.media.MediaSession2;
 import android.media.MediaSession2.Command;
+import android.media.MediaSession2.CommandButton.Builder;
 import android.media.MediaSession2.CommandGroup;
 import android.media.MediaSession2.ControllerInfo;
+import android.media.MediaSession2.PlaylistParams;
 import android.media.MediaSession2.SessionCallback;
 import android.media.MediaSessionService2;
+import android.media.MediaSessionService2.MediaNotification;
+import android.media.PlaybackState2;
+import android.media.Rating2;
 import android.media.SessionPlayer2;
 import android.media.SessionToken2;
-import android.media.VolumeProvider;
+import android.media.VolumeProvider2;
 import android.media.update.MediaBrowser2Provider;
 import android.media.update.MediaControlView2Provider;
 import android.media.update.MediaController2Provider;
 import android.media.update.MediaItem2Provider;
-import android.media.update.MediaLibraryService2Provider.MediaLibrarySessionProvider;
+import android.media.update.MediaLibraryService2Provider.LibraryRootProvider;
+import android.media.update.MediaMetadata2Provider;
 import android.media.update.MediaSession2Provider;
+import android.media.update.MediaSession2Provider.BuilderBaseProvider;
+import android.media.update.MediaSession2Provider.CommandButtonProvider.BuilderProvider;
+import android.media.update.MediaSession2Provider.PlaylistParamsProvider;
 import android.media.update.MediaSessionService2Provider;
+import android.media.update.MediaSessionService2Provider.MediaNotificationProvider;
+import android.media.update.PlaybackState2Provider;
 import android.media.update.SessionPlayer2Provider;
 import android.media.update.SessionToken2Provider;
-import android.media.update.VideoView2Provider;
 import android.media.update.StaticProvider;
+import android.media.update.VideoView2Provider;
 import android.media.update.ViewProvider;
+import android.media.update.VolumeProvider2Provider;
 import android.os.Bundle;
 import android.os.IInterface;
 import android.support.annotation.Nullable;
@@ -59,16 +73,20 @@
 import android.widget.MediaControlView2;
 import android.widget.VideoView2;
 
-import com.android.media.IMediaSession2;
 import com.android.media.IMediaSession2Callback;
 import com.android.media.MediaBrowser2Impl;
 import com.android.media.MediaController2Impl;
 import com.android.media.MediaItem2Impl;
 import com.android.media.MediaLibraryService2Impl;
-import com.android.media.MediaLibraryService2Impl.MediaLibrarySessionImpl;
+import com.android.media.MediaLibraryService2Impl.LibraryRootImpl;
+import com.android.media.MediaMetadata2Impl;
 import com.android.media.MediaSession2Impl;
+import com.android.media.MediaSession2Impl.PlaylistParamsImpl;
 import com.android.media.MediaSessionService2Impl;
+import com.android.media.PlaybackState2Impl;
+import com.android.media.Rating2Impl;
 import com.android.media.SessionToken2Impl;
+import com.android.media.VolumeProvider2Impl;
 import com.android.widget.MediaControlView2Impl;
 import com.android.widget.VideoView2Impl;
 
@@ -95,15 +113,6 @@
     }
 
     @Override
-    public MediaSession2Provider createMediaSession2(Context context, MediaSession2 instance,
-            MediaPlayerInterface player, String id, VolumeProvider volumeProvider,
-            int ratingType, PendingIntent sessionActivity, Executor callbackExecutor,
-            SessionCallback callback) {
-        return new MediaSession2Impl(context, instance, player, id, volumeProvider, ratingType,
-                sessionActivity, callbackExecutor, callback);
-    }
-
-    @Override
     public MediaSession2Provider.CommandProvider createMediaSession2Command(
             Command instance, int commandCode, String action, Bundle extra) {
         if (action == null && extra == null) {
@@ -130,7 +139,7 @@
     }
 
     @Override
-    public MediaSession2Provider.ControllerInfoProvider createMediaSession2ControllerInfoProvider(
+    public MediaSession2Provider.ControllerInfoProvider createMediaSession2ControllerInfo(
             Context context, ControllerInfo instance, int uid, int pid, String packageName,
             IInterface callback) {
         return new MediaSession2Impl.ControllerInfoImpl(context,
@@ -138,24 +147,61 @@
     }
 
     @Override
+    public PlaylistParamsProvider createMediaSession2PlaylistParams(Context context,
+            PlaylistParams playlistParams, int repeatMode, int shuffleMode,
+            MediaMetadata2 playlistMetadata) {
+        return new PlaylistParamsImpl(context, playlistParams, repeatMode, shuffleMode,
+                playlistMetadata);
+    }
+
+    @Override
+    public PlaylistParams fromBundle_PlaylistParams(Context context, Bundle bundle) {
+        return PlaylistParamsImpl.fromBundle(context, bundle);
+    }
+
+    @Override
+    public BuilderProvider createMediaSession2CommandButtonBuilder(Context context,
+            Builder instance) {
+        return new MediaSession2Impl.CommandButtonImpl.BuilderImpl(context, instance);
+    }
+
+    public BuilderBaseProvider<MediaSession2, SessionCallback> createMediaSession2Builder(
+            Context context, MediaSession2.Builder instance, MediaPlayerInterface player) {
+        return new MediaSession2Impl.BuilderImpl(context, instance, player);
+    }
+
+    @Override
     public MediaSessionService2Provider createMediaSessionService2(
             MediaSessionService2 instance) {
         return new MediaSessionService2Impl(instance);
     }
 
     @Override
+    public MediaNotificationProvider createMediaSessionService2MediaNotification(Context context,
+            MediaNotification instance, int notificationId, Notification notification) {
+        return new MediaSessionService2Impl.MediaNotificationImpl(
+                context, instance, notificationId, notification);
+    }
+
+    @Override
     public MediaSessionService2Provider createMediaLibraryService2(
             MediaLibraryService2 instance) {
         return new MediaLibraryService2Impl(instance);
     }
 
     @Override
-    public MediaLibrarySessionProvider createMediaLibraryService2MediaLibrarySession(
-            Context context, MediaLibrarySession instance, MediaPlayerInterface player,
-            String id, VolumeProvider volumeProvider, int ratingType, PendingIntent sessionActivity,
+    public BuilderBaseProvider<MediaLibrarySession, MediaLibrarySessionCallback>
+        createMediaLibraryService2Builder(
+            Context context, MediaLibrarySessionBuilder instance, MediaPlayerInterface player,
             Executor callbackExecutor, MediaLibrarySessionCallback callback) {
-        return new MediaLibrarySessionImpl(context, instance, player, id, volumeProvider,
-                ratingType, sessionActivity, callbackExecutor, callback);
+        return new MediaLibraryService2Impl.BuilderImpl(context, instance, player, callbackExecutor,
+                callback);
+    }
+
+    @Override
+    public LibraryRootProvider createMediaLibraryService2LibraryRoot(Context context,
+            LibraryRoot instance, String rootId, Bundle extras) {
+        return new LibraryRootImpl(context, instance, rootId, extras);
     }
 
     @Override
@@ -189,7 +235,7 @@
     }
 
     @Override
-    public MediaItem2Provider createMediaItem2Provider(Context context, MediaItem2 instance,
+    public MediaItem2Provider createMediaItem2(Context context, MediaItem2 instance,
             String mediaId, DataSourceDesc dsd, MediaMetadata2 metadata, int flags) {
         return new MediaItem2Impl(context, instance, mediaId, dsd, metadata, flags);
     }
@@ -198,4 +244,70 @@
     public MediaItem2 fromBundle_MediaItem2(Context context, Bundle bundle) {
         return MediaItem2Impl.fromBundle(context, bundle);
     }
+
+    @Override
+    public VolumeProvider2Provider createVolumeProvider2(Context context, VolumeProvider2 instance,
+            int controlType, int maxVolume, int currentVolume) {
+        return new VolumeProvider2Impl(context, instance, controlType, maxVolume, currentVolume);
+    }
+
+    @Override
+    public MediaMetadata2 fromBundle_MediaMetadata2(Context context, Bundle bundle) {
+        return MediaMetadata2Impl.fromBundle(context, bundle);
+    }
+
+    @Override
+    public MediaMetadata2Provider.BuilderProvider createMediaMetadata2Builder(
+            Context context, MediaMetadata2.Builder builder) {
+        return new MediaMetadata2Impl.BuilderImpl(context, builder);
+    }
+
+    @Override
+    public MediaMetadata2Provider.BuilderProvider createMediaMetadata2Builder(
+            Context context, MediaMetadata2.Builder builder, MediaMetadata2 source) {
+        return new MediaMetadata2Impl.BuilderImpl(context, builder, source);
+    }
+
+    @Override
+    public Rating2 fromBundle_Rating2(Context context, Bundle bundle) {
+        return Rating2Impl.fromBundle(context, bundle);
+    }
+
+    @Override
+    public Rating2 newUnratedRating_Rating2(Context context, int ratingStyle) {
+        return Rating2Impl.newUnratedRating(context, ratingStyle);
+    }
+
+    @Override
+    public Rating2 newHeartRating_Rating2(Context context, boolean hasHeart) {
+        return Rating2Impl.newHeartRating(context, hasHeart);
+    }
+
+    @Override
+    public Rating2 newThumbRating_Rating2(Context context, boolean thumbIsUp) {
+        return Rating2Impl.newThumbRating(context, thumbIsUp);
+    }
+
+    @Override
+    public Rating2 newStarRating_Rating2(Context context, int starRatingStyle, float starRating) {
+        return Rating2Impl.newStarRating(context, starRatingStyle, starRating);
+    }
+
+    @Override
+    public Rating2 newPercentageRating_Rating2(Context context, float percent) {
+        return Rating2Impl.newPercentageRating(context, percent);
+    }
+
+    @Override
+    public PlaybackState2Provider createPlaybackState2(Context context, PlaybackState2 instance,
+            int state, long position, long updateTime, float speed, long bufferedPosition,
+            long activeItemId, CharSequence error) {
+        return new PlaybackState2Impl(context, instance, state, position, updateTime, speed,
+                bufferedPosition, activeItemId, error);
+    }
+
+    @Override
+    public PlaybackState2 fromBundle_PlaybackState2(Context context, Bundle bundle) {
+        return PlaybackState2Impl.fromBundle(context, bundle);
+    }
 }
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteButton.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteButton.java
index 65fc88c..7fdcfe4 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteButton.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteButton.java
@@ -90,6 +90,7 @@
     private final MediaRouterCallback mCallback;
 
     private MediaRouteSelector mSelector = MediaRouteSelector.EMPTY;
+    private int mRouteCallbackFlags;
     private MediaRouteDialogFactory mDialogFactory = MediaRouteDialogFactory.getDefault();
 
     private boolean mAttachedToWindow;
@@ -174,23 +175,38 @@
      * Sets the media route selector for filtering the routes that the user can
      * select using the media route chooser dialog.
      *
-     * @param selector The selector, must not be null.
+     * @param selector The selector.
      */
     public void setRouteSelector(MediaRouteSelector selector) {
-        if (selector == null) {
-            throw new IllegalArgumentException("selector must not be null");
+        setRouteSelector(selector, 0);
+    }
+
+    /**
+     * Sets the media route selector for filtering the routes that the user can
+     * select using the media route chooser dialog.
+     *
+     * @param selector The selector.
+     * @param flags Flags to control the behavior of the callback. May be zero or a combination of
+     *              {@link #MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN} and
+     *              {@link #MediaRouter.CALLBACK_FLAG_UNFILTERED_EVENTS}.
+     */
+    public void setRouteSelector(MediaRouteSelector selector, int flags) {
+        if (mSelector.equals(selector) && mRouteCallbackFlags == flags) {
+            return;
+        }
+        if (!mSelector.isEmpty()) {
+            mRouter.removeCallback(mCallback);
+        }
+        if (selector == null || selector.isEmpty()) {
+            mSelector = MediaRouteSelector.EMPTY;
+            return;
         }
 
-        if (!mSelector.equals(selector)) {
-            if (mAttachedToWindow) {
-                if (!mSelector.isEmpty()) {
-                    mRouter.removeCallback(mCallback);
-                }
-                if (!selector.isEmpty()) {
-                    mRouter.addCallback(selector, mCallback);
-                }
-            }
-            mSelector = selector;
+        mSelector = selector;
+        mRouteCallbackFlags = flags;
+
+        if (mAttachedToWindow) {
+            mRouter.addCallback(selector, mCallback, flags);
             refreshRoute();
         }
     }
@@ -411,7 +427,7 @@
 
         mAttachedToWindow = true;
         if (!mSelector.isEmpty()) {
-            mRouter.addCallback(mSelector, mCallback);
+            mRouter.addCallback(mSelector, mCallback, mRouteCallbackFlags);
         }
         refreshRoute();
     }
diff --git a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
index b4aaa79..138232e 100644
--- a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
@@ -38,6 +38,9 @@
 
 import com.android.media.update.ApiHelper;
 import com.android.media.update.R;
+import com.android.support.mediarouter.app.MediaRouteButton;
+import com.android.support.mediarouter.media.MediaRouter;
+import com.android.support.mediarouter.media.MediaRouteSelector;
 
 import java.util.Formatter;
 import java.util.List;
@@ -107,6 +110,9 @@
     private StringBuilder mFormatBuilder;
     private Formatter mFormatter;
 
+    private MediaRouteButton mRouteButton;
+    private MediaRouteSelector mRouteSelector;
+
     public MediaControlView2Impl(
             MediaControlView2 instance, ViewProvider superProvider) {
         mInstance = instance;
@@ -305,6 +311,17 @@
         mSuperProvider.setEnabled_impl(enabled);
     }
 
+    public void setRouteSelector(MediaRouteSelector selector) {
+        mRouteSelector = selector;
+        if (mRouteSelector != null && !mRouteSelector.isEmpty()) {
+            mRouteButton.setRouteSelector(selector, MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
+            mRouteButton.setVisibility(View.VISIBLE);
+        } else {
+            mRouteButton.setRouteSelector(MediaRouteSelector.EMPTY);
+            mRouteButton.setVisibility(View.GONE);
+        }
+    }
+
     ///////////////////////////////////////////////////
     // Protected or private methods
     ///////////////////////////////////////////////////
@@ -375,6 +392,8 @@
         mPauseDescription = res.getText(R.string.lockscreen_pause_button_content_description);
         mReplayDescription = res.getText(R.string.lockscreen_replay_button_content_description);
 
+        mRouteButton = v.findViewById(R.id.cast);
+
         mPlayPauseButton = v.findViewById(R.id.pause);
         if (mPlayPauseButton != null) {
             mPlayPauseButton.requestFocus();
diff --git a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
index a8864fc..7218150 100644
--- a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
@@ -35,6 +35,7 @@
 import android.media.TtmlRenderer;
 import android.media.WebVttRenderer;
 import android.media.session.MediaController;
+import android.media.session.MediaController.PlaybackInfo;
 import android.media.session.MediaSession;
 import android.media.session.PlaybackState;
 import android.media.update.VideoView2Provider;
@@ -103,7 +104,7 @@
     private MediaController mMediaController;
     private MediaSession.Callback mRouteSessionCallback = new RouteSessionCallback();
     private MediaRouter mMediaRouter;
-    private MediaRouteSelector mMediaRouteSelector;
+    private MediaRouteSelector mRouteSelector;
     private Metadata mMetadata;
     private String mTitle;
 
@@ -172,16 +173,38 @@
 
         // TODO: Need a common namespace for attributes those are defined in updatable library.
         boolean enableControlView = (attrs == null) || attrs.getAttributeBooleanValue(
-                "http://schemas.android.com/apk/com.android.media.update",
+                "http://schemas.android.com/apk/res/android",
                 "enableControlView", true);
         if (enableControlView) {
             mMediaControlView = new MediaControlView2(mInstance.getContext());
         }
+        boolean showSubtitle = (attrs == null) || attrs.getAttributeBooleanValue(
+                "http://schemas.android.com/apk/res/android",
+                "showSubtitle", true);
+        if (showSubtitle) {
+            Log.d(TAG, "showSubtitle attribute is true.");
+            // TODO: implement
+        }
+        int viewType = (attrs == null) ? VideoView2.VIEW_TYPE_SURFACEVIEW
+                : attrs.getAttributeIntValue(
+                "http://schemas.android.com/apk/res/android",
+                "viewType", 0);
+        if (viewType == 0) {
+            Log.d(TAG, "viewType attribute is surfaceView.");
+            // TODO: implement
+        } else if (viewType == 1) {
+            Log.d(TAG, "viewType attribute is textureView.");
+            // TODO: implement
+        }
     }
 
     @Override
     public void setMediaControlView2_impl(MediaControlView2 mediaControlView) {
         mMediaControlView = mediaControlView;
+        if (mRouteSelector != null) {
+            ((MediaControlView2Impl) mMediaControlView.getProvider())
+                    .setRouteSelector(mRouteSelector);
+        }
 
         if (mInstance.isAttachedToWindow()) {
             attachMediaControlView();
@@ -202,30 +225,29 @@
     }
 
     @Override
-    public void showSubtitle_impl() {
-        // Retrieve all tracks that belong to the current video.
-        MediaPlayer.TrackInfo[] trackInfos = mMediaPlayer.getTrackInfo();
+    public void showSubtitle_impl(boolean show) {
+        if (show) {
+            // Retrieve all tracks that belong to the current video.
+            MediaPlayer.TrackInfo[] trackInfos = mMediaPlayer.getTrackInfo();
 
-        List<Integer> subtitleTrackIndices = new ArrayList<>();
-        for (int i = 0; i < trackInfos.length; ++i) {
-            int trackType = trackInfos[i].getTrackType();
-            if (trackType == MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
-                subtitleTrackIndices.add(i);
+            List<Integer> subtitleTrackIndices = new ArrayList<>();
+            for (int i = 0; i < trackInfos.length; ++i) {
+                int trackType = trackInfos[i].getTrackType();
+                if (trackType == MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
+                    subtitleTrackIndices.add(i);
+                }
             }
-        }
-        if (subtitleTrackIndices.size() > 0) {
-            // Select first subtitle track
-            mCCEnabled = true;
-            mSelectedTrackIndex = subtitleTrackIndices.get(0);
-            mMediaPlayer.selectTrack(mSelectedTrackIndex);
-        }
-    }
-
-    @Override
-    public void hideSubtitle_impl() {
-        if (mCCEnabled) {
-            mMediaPlayer.deselectTrack(mSelectedTrackIndex);
-            mCCEnabled = false;
+            if (subtitleTrackIndices.size() > 0) {
+                // Select first subtitle track
+                mCCEnabled = true;
+                mSelectedTrackIndex = subtitleTrackIndices.get(0);
+                mMediaPlayer.selectTrack(mSelectedTrackIndex);
+            }
+        } else {
+            if (mCCEnabled) {
+                mMediaPlayer.deselectTrack(mSelectedTrackIndex);
+                mCCEnabled = false;
+            }
         }
     }
 
@@ -275,7 +297,11 @@
         for (String category : routeCategories) {
             builder.addControlCategory(category);
         }
-        mMediaRouteSelector = builder.build();
+        mRouteSelector = builder.build();
+        if (mMediaControlView != null) {
+            ((MediaControlView2Impl) mMediaControlView.getProvider())
+                    .setRouteSelector(mRouteSelector);
+        }
         mMediaRouter = MediaRouter.getInstance(mInstance.getContext());
         mRouteSessionCallback = sessionPlayer;
         if (mMediaSession != null) {
@@ -386,6 +412,7 @@
 
     @Override
     public void onDetachedFromWindow_impl() {
+        Log.e(TAG, ".... Debugging. onDetachedFromWindow_impl()");
         mSuperProvider.onDetachedFromWindow_impl();
         mMediaSession.release();
         mMediaSession = null;
@@ -703,6 +730,14 @@
         }
     }
 
+    private boolean isRemotePlayback() {
+        if (mMediaController == null) {
+            return false;
+        }
+        PlaybackInfo playbackInfo = mMediaController.getPlaybackInfo();
+        return (playbackInfo != null) && (playbackInfo.getPlaybackType() == PlaybackInfo.PLAYBACK_TYPE_REMOTE);
+    }
+
     MediaPlayer.OnVideoSizeChangedListener mSizeChangedListener =
             new MediaPlayer.OnVideoSizeChangedListener() {
                 public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
@@ -895,16 +930,15 @@
     private class MediaSessionCallback extends MediaSession.Callback {
         @Override
         public void onCommand(String command, Bundle args, ResultReceiver receiver) {
-            if (mMediaController.getPlaybackInfo().getPlaybackType()
-                    == MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE) {
+            if (isRemotePlayback()) {
                 mRouteSessionCallback.onCommand(command, args, receiver);
             } else {
                 switch (command) {
                     case MediaControlView2.COMMAND_SHOW_SUBTITLE:
-                        mInstance.showSubtitle();
+                        mInstance.showSubtitle(true);
                         break;
                     case MediaControlView2.COMMAND_HIDE_SUBTITLE:
-                        mInstance.hideSubtitle();
+                        mInstance.showSubtitle(false);
                         break;
                     case MediaControlView2.COMMAND_SET_FULLSCREEN:
                         if (mOnFullScreenRequestListener != null) {
@@ -924,8 +958,7 @@
 
         @Override
         public void onPlay() {
-            if (mMediaController.getPlaybackInfo().getPlaybackType()
-                    == MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE) {
+            if (isRemotePlayback()) {
                 mRouteSessionCallback.onPlay();
             } else {
                 if (isInPlaybackState() && mCurrentView.hasAvailableSurface()) {
@@ -944,8 +977,7 @@
 
         @Override
         public void onPause() {
-            if (mMediaController.getPlaybackInfo().getPlaybackType()
-                    == MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE) {
+            if (isRemotePlayback()) {
                 mRouteSessionCallback.onPause();
             } else {
                 if (isInPlaybackState()) {
@@ -965,8 +997,7 @@
 
         @Override
         public void onSeekTo(long pos) {
-            if (mMediaController.getPlaybackInfo().getPlaybackType()
-                    == MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE) {
+            if (isRemotePlayback()) {
                 mRouteSessionCallback.onSeekTo(pos);
             } else {
                 if (isInPlaybackState()) {
@@ -981,8 +1012,7 @@
 
         @Override
         public void onStop() {
-            if (mMediaController.getPlaybackInfo().getPlaybackType()
-                    == MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE) {
+            if (isRemotePlayback()) {
                 mRouteSessionCallback.onStop();
             } else {
                 resetPlayer();
diff --git a/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java b/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java
index 50e59b8..38475a8 100644
--- a/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java
+++ b/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java
@@ -66,7 +66,7 @@
     }
 
     @Test
-    public void testGetBrowserRoot() throws InterruptedException {
+    public void testGetLibraryRoot() throws InterruptedException {
         final Bundle param = new Bundle();
         param.putString(TAG, TAG);
 
@@ -84,7 +84,7 @@
         final SessionToken2 token = MockMediaLibraryService2.getToken(mContext);
         MediaBrowser2 browser =
                 (MediaBrowser2) createController(token,true, callback);
-        browser.getBrowserRoot(param);
+        browser.getLibraryRoot(param);
         assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
     }
 
diff --git a/packages/MediaComponents/test/src/android/media/MediaController2Test.java b/packages/MediaComponents/test/src/android/media/MediaController2Test.java
index 27dbaf8..e8eaa20 100644
--- a/packages/MediaComponents/test/src/android/media/MediaController2Test.java
+++ b/packages/MediaComponents/test/src/android/media/MediaController2Test.java
@@ -42,7 +42,8 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-import static android.media.TestUtils.createPlaybackState;
+import static android.media.TestUtils.ensurePlaylistParamsModeEquals;
+
 import static org.junit.Assert.*;
 
 /**
@@ -200,7 +201,7 @@
 
     @Test
     public void testGetSetPlaylistParams() throws Exception {
-        final PlaylistParams params = new PlaylistParams(
+        final PlaylistParams params = new PlaylistParams(mContext,
                 PlaylistParams.REPEAT_MODE_ALL,
                 PlaylistParams.SHUFFLE_MODE_ALL,
                 null /* PlaylistMetadata */);
@@ -209,7 +210,7 @@
         final TestControllerCallbackInterface callback = new TestControllerCallbackInterface() {
             @Override
             public void onPlaylistParamsChanged(PlaylistParams givenParams) {
-                TestUtils.equals(params.toBundle(), givenParams.toBundle());
+                ensurePlaylistParamsModeEquals(params, givenParams);
                 latch.countDown();
             }
         };
@@ -218,8 +219,8 @@
         controller.setPlaylistParams(params);
 
         assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
-        TestUtils.equals(params.toBundle(), mSession.getPlaylistParams().toBundle());
-        TestUtils.equals(params.toBundle(), controller.getPlaylistParams().toBundle());
+        ensurePlaylistParamsModeEquals(params, mSession.getPlaylistParams());
+        ensurePlaylistParamsModeEquals(params, controller.getPlaylistParams());
     }
 
     @Test
diff --git a/packages/MediaComponents/test/src/android/media/MediaMetadata2Test.java b/packages/MediaComponents/test/src/android/media/MediaMetadata2Test.java
new file mode 100644
index 0000000..ea42651
--- /dev/null
+++ b/packages/MediaComponents/test/src/android/media/MediaMetadata2Test.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2018 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.
+ */
+
+package android.media;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
+import android.content.Context;
+import android.media.MediaMetadata2.Builder;
+import android.os.Bundle;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class MediaMetadata2Test {
+    private Context mContext;
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
+    }
+
+    @Test
+    public void testBuilder() {
+        final Bundle extra = new Bundle();
+        extra.putString("MediaMetadata2Test", "testBuilder");
+        final String title = "title";
+        final long discNumber = 10;
+        final Rating2 rating = Rating2.newThumbRating(mContext, true);
+
+        MediaMetadata2.Builder builder = new Builder(mContext);
+        builder.setExtra(extra);
+        builder.putString(MediaMetadata2.METADATA_KEY_DISPLAY_TITLE, title);
+        builder.putLong(MediaMetadata2.METADATA_KEY_DISC_NUMBER, discNumber);
+        builder.putRating(MediaMetadata2.METADATA_KEY_USER_RATING, rating);
+
+        MediaMetadata2 metadata = builder.build();
+        assertTrue(TestUtils.equals(extra, metadata.getExtra()));
+        assertEquals(title, metadata.getString(MediaMetadata2.METADATA_KEY_DISPLAY_TITLE));
+        assertEquals(discNumber, metadata.getLong(MediaMetadata2.METADATA_KEY_DISC_NUMBER));
+        assertEquals(rating, metadata.getRating(MediaMetadata2.METADATA_KEY_USER_RATING));
+    }
+}
diff --git a/packages/MediaComponents/test/src/android/media/MediaSession2Test.java b/packages/MediaComponents/test/src/android/media/MediaSession2Test.java
index c5bcfff..ff8c2b7 100644
--- a/packages/MediaComponents/test/src/android/media/MediaSession2Test.java
+++ b/packages/MediaComponents/test/src/android/media/MediaSession2Test.java
@@ -19,7 +19,7 @@
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertTrue;
 
-import static android.media.TestUtils.createPlaybackState;
+import static android.media.TestUtils.ensurePlaylistParamsModeEquals;
 
 import android.media.MediaPlayerInterface.PlaybackListener;
 import android.media.MediaSession2.Builder;
@@ -170,7 +170,7 @@
 
     @Test
     public void testSetPlaylistParams() throws Exception {
-        final PlaylistParams params = new PlaylistParams(
+        final PlaylistParams params = new PlaylistParams(mContext,
                 PlaylistParams.REPEAT_MODE_ALL,
                 PlaylistParams.SHUFFLE_MODE_ALL,
                 null /* PlaylistMetadata */);
@@ -179,7 +179,7 @@
         final TestControllerCallbackInterface callback = new TestControllerCallbackInterface() {
             @Override
             public void onPlaylistParamsChanged(PlaylistParams givenParams) {
-                TestUtils.equals(params.toBundle(), givenParams.toBundle());
+                ensurePlaylistParamsModeEquals(params, givenParams);
                 latch.countDown();
             }
         };
@@ -187,8 +187,8 @@
         final MediaController2 controller = createController(mSession.getToken(), true, callback);
         mSession.setPlaylistParams(params);
         assertTrue(mPlayer.mSetPlaylistParamsCalled);
-        TestUtils.equals(params.toBundle(), mPlayer.mPlaylistParams.toBundle());
-        TestUtils.equals(params.toBundle(), mSession.getPlaylistParams().toBundle());
+        ensurePlaylistParamsModeEquals(params, mPlayer.mPlaylistParams);
+        ensurePlaylistParamsModeEquals(params, mSession.getPlaylistParams());
         assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
     }
 
@@ -390,7 +390,7 @@
 
             assertEquals(aItem.getMediaId(), bItem.getMediaId());
             assertEquals(aItem.getFlags(), bItem.getFlags());
-            TestUtils.equals(aItem.getMetadata().getBundle(), bItem.getMetadata().getBundle());
+            TestUtils.equals(aItem.getMetadata().toBundle(), bItem.getMetadata().toBundle());
 
             // Note: Here it does not check whether DataSourceDesc are equal,
             // since there DataSourceDec is not comparable.
diff --git a/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java b/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java
index 8e1c782..5d94b17 100644
--- a/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java
+++ b/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java
@@ -108,6 +108,17 @@
         }
     }
 
+    /**
+     * Creates a {@link android.media.session.PlaybackState} with the given state.
+     *
+     * @param state one of the PlaybackState.STATE_xxx.
+     * @return a PlaybackState
+     */
+    public PlaybackState2 createPlaybackState(int state) {
+        return new PlaybackState2(mContext, state, 0, 0, 1.0f,
+                0, 0, null);
+    }
+
     final MediaController2 createController(SessionToken2 token) throws InterruptedException {
         return createController(token, true, null);
     }
diff --git a/packages/MediaComponents/test/src/android/media/MediaSessionManager_MediaSession2.java b/packages/MediaComponents/test/src/android/media/MediaSessionManager_MediaSession2.java
index 96ae8b7..852f2fa 100644
--- a/packages/MediaComponents/test/src/android/media/MediaSessionManager_MediaSession2.java
+++ b/packages/MediaComponents/test/src/android/media/MediaSessionManager_MediaSession2.java
@@ -33,7 +33,6 @@
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
-import static android.media.TestUtils.createPlaybackState;
 import static org.junit.Assert.*;
 
 /**
diff --git a/packages/MediaComponents/test/src/android/media/MockMediaLibraryService2.java b/packages/MediaComponents/test/src/android/media/MockMediaLibraryService2.java
index 6e1501a..ec69ff6 100644
--- a/packages/MediaComponents/test/src/android/media/MockMediaLibraryService2.java
+++ b/packages/MediaComponents/test/src/android/media/MockMediaLibraryService2.java
@@ -97,8 +97,8 @@
         }
 
         @Override
-        public BrowserRoot onGetRoot(ControllerInfo controller, Bundle rootHints) {
-            return new BrowserRoot(ROOT_ID, EXTRA);
+        public LibraryRoot onGetRoot(ControllerInfo controller, Bundle rootHints) {
+            return new LibraryRoot(MockMediaLibraryService2.this, ROOT_ID, EXTRA);
         }
     }
 }
\ No newline at end of file
diff --git a/packages/MediaComponents/test/src/android/media/MockMediaSessionService2.java b/packages/MediaComponents/test/src/android/media/MockMediaSessionService2.java
index d85875e..c8ed184 100644
--- a/packages/MediaComponents/test/src/android/media/MockMediaSessionService2.java
+++ b/packages/MediaComponents/test/src/android/media/MockMediaSessionService2.java
@@ -87,7 +87,7 @@
                 .setContentTitle(getPackageName())
                 .setContentText("Playback state: " + state.getState())
                 .setSmallIcon(android.R.drawable.sym_def_app_icon).build();
-        return MediaNotification.create(DEFAULT_MEDIA_NOTIFICATION_ID, notification);
+        return new MediaNotification(this, DEFAULT_MEDIA_NOTIFICATION_ID, notification);
     }
 
     private class MySessionCallback extends SessionCallback {
diff --git a/packages/MediaComponents/test/src/android/media/TestUtils.java b/packages/MediaComponents/test/src/android/media/TestUtils.java
index 9a1fa10..12b24c0 100644
--- a/packages/MediaComponents/test/src/android/media/TestUtils.java
+++ b/packages/MediaComponents/test/src/android/media/TestUtils.java
@@ -17,6 +17,7 @@
 package android.media;
 
 import android.content.Context;
+import android.media.MediaSession2.PlaylistParams;
 import android.media.session.MediaSessionManager;
 import android.media.session.PlaybackState;
 import android.os.Bundle;
@@ -29,6 +30,7 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -40,17 +42,6 @@
     private static final int WAIT_SERVICE_TIME_MS = 5000;
 
     /**
-     * Creates a {@link android.media.session.PlaybackState} with the given state.
-     *
-     * @param state one of the PlaybackState.STATE_xxx.
-     * @return a PlaybackState
-     */
-    public static PlaybackState2 createPlaybackState(int state) {
-        return new PlaybackState2(state, 0, 0, 1.0f,
-                0, 0, null);
-    }
-
-    /**
      * Finds the session with id in this test package.
      *
      * @param context
@@ -100,6 +91,11 @@
         return true;
     }
 
+    public static void ensurePlaylistParamsModeEquals(PlaylistParams a, PlaylistParams b) {
+        assertEquals(a.getRepeatMode(), b.getRepeatMode());
+        assertEquals(a.getShuffleMode(), b.getShuffleMode());
+    }
+
     /**
      * Handler that always waits until the Runnable finishes.
      */
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 83caca7..7c38bcc 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -559,6 +559,8 @@
         virtual binder::Status    start(int /*AudioSystem::sync_event_t*/ event,
                 int /*audio_session_t*/ triggerSession);
         virtual binder::Status   stop();
+        virtual binder::Status   getActiveMicrophones(
+                std::vector<media::MicrophoneInfo>* activeMicrophones);
     private:
         const sp<RecordThread::RecordTrack> mRecordTrack;
 
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index 63a3d98..1733ef5 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -66,6 +66,8 @@
             void        setSilenced(bool silenced) { mSilenced = silenced; }
             bool        isSilenced() const { return mSilenced; }
 
+            status_t    getActiveMicrophones(std::vector<media::MicrophoneInfo>* activeMicrophones);
+
 private:
     friend class AudioFlinger;  // for mState
 
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 420e6e1..14d7e2e 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -7043,6 +7043,49 @@
 #endif
 }
 
+status_t AudioFlinger::RecordThread::getActiveMicrophones(
+        std::vector<media::MicrophoneInfo>* activeMicrophones)
+{
+    ALOGV("RecordThread::getActiveMicrophones");
+    AutoMutex _l(mLock);
+    // Fake data
+    struct audio_microphone_characteristic_t characteristic;
+    sprintf(characteristic.device_id, "builtin_mic");
+    characteristic.type = AUDIO_DEVICE_IN_BUILTIN_MIC;
+    sprintf(characteristic.address, "");
+    characteristic.location = AUDIO_MICROPHONE_LOCATION_MAINBODY;
+    characteristic.group = 0;
+    characteristic.index_in_the_group = 0;
+    characteristic.sensitivity = 1.0f;
+    characteristic.max_spl = 100.0f;
+    characteristic.min_spl = 0.0f;
+    characteristic.directionality = AUDIO_MICROPHONE_DIRECTIONALITY_OMNI;
+    characteristic.num_frequency_responses = 5;
+    for (size_t i = 0; i < characteristic.num_frequency_responses; i++) {
+        characteristic.frequency_responses[0][i] = 100.0f - i;
+        characteristic.frequency_responses[1][i] = 100.0f + i;
+    }
+    for (size_t i = 0; i < AUDIO_CHANNEL_COUNT_MAX; i++) {
+        characteristic.channel_mapping[i] = AUDIO_MICROPHONE_CHANNEL_MAPPING_UNUSED;
+    }
+    audio_microphone_channel_mapping_t channel_mappings[] = {
+        AUDIO_MICROPHONE_CHANNEL_MAPPING_DIRECT,
+        AUDIO_MICROPHONE_CHANNEL_MAPPING_PROCESSED,
+    };
+    for (size_t i = 0; i < mChannelCount; i++) {
+        characteristic.channel_mapping[i] = channel_mappings[i % 2];
+    }
+    characteristic.geometric_location.x = 0.1f;
+    characteristic.geometric_location.y = 0.2f;
+    characteristic.geometric_location.z = 0.3f;
+    characteristic.orientation.x = 0.0f;
+    characteristic.orientation.y = 1.0f;
+    characteristic.orientation.z = 0.0f;
+    media::MicrophoneInfo microphoneInfo = media::MicrophoneInfo(characteristic);
+    activeMicrophones->push_back(microphoneInfo);
+    return NO_ERROR;
+}
+
 // destroyTrack_l() must be called with ThreadBase::mLock held
 void AudioFlinger::RecordThread::destroyTrack_l(const sp<RecordTrack>& track)
 {
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index eb29497..53cb8ad 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1398,6 +1398,8 @@
             // Sets the UID records silence
             void        setRecordSilenced(uid_t uid, bool silenced);
 
+            status_t    getActiveMicrophones(std::vector<media::MicrophoneInfo>* activeMicrophones);
+
 private:
             // Enter standby if not already in standby, and set mStandby flag
             void    standbyIfNotAlreadyInStandby();
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index cdd8ca0..ce5c53b 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1580,6 +1580,13 @@
     mRecordTrack->stop();
 }
 
+binder::Status AudioFlinger::RecordHandle::getActiveMicrophones(
+        std::vector<media::MicrophoneInfo>* activeMicrophones) {
+    ALOGV("RecordHandle::getActiveMicrophones()");
+    return binder::Status::fromStatusT(
+            mRecordTrack->getActiveMicrophones(activeMicrophones));
+}
+
 // ----------------------------------------------------------------------------
 
 // RecordTrack constructor must be called with AudioFlinger::mLock and ThreadBase::mLock held
@@ -1792,6 +1799,18 @@
     mServerProxy->setTimestamp(local);
 }
 
+status_t AudioFlinger::RecordThread::RecordTrack::getActiveMicrophones(
+        std::vector<media::MicrophoneInfo>* activeMicrophones)
+{
+    sp<ThreadBase> thread = mThread.promote();
+    if (thread != 0) {
+        RecordThread *recordThread = (RecordThread *)thread.get();
+        return recordThread->getActiveMicrophones(activeMicrophones);
+    } else {
+        return BAD_VALUE;
+    }
+}
+
 AudioFlinger::RecordThread::PatchRecord::PatchRecord(RecordThread *recordThread,
                                                      uint32_t sampleRate,
                                                      audio_channel_mask_t channelMask,
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 7343601..40e0199 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1427,7 +1427,7 @@
     // Explicit routing?
     sp<DeviceDescriptor> deviceDesc;
     if (*selectedDeviceId != AUDIO_PORT_HANDLE_NONE) {
-        deviceDesc = mAvailableOutputDevices.getDeviceFromId(*selectedDeviceId);
+        deviceDesc = mAvailableInputDevices.getDeviceFromId(*selectedDeviceId);
     }
     mInputRoutes.addRoute(session, SessionRoute::STREAM_TYPE_NA, inputSource, deviceDesc, uid);
 
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index e5aed9a..90a5a0f 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -273,7 +273,7 @@
 void AudioPolicyService::NotificationClient::onDynamicPolicyMixStateUpdate(
         const String8& regId, int32_t state)
 {
-    if (mAudioPolicyServiceClient != 0) {
+    if (mAudioPolicyServiceClient != 0 && mUid < AID_APP_START) {
         mAudioPolicyServiceClient->onDynamicPolicyMixStateUpdate(regId, state);
     }
 }
@@ -283,7 +283,7 @@
         const audio_config_base_t *clientConfig, const audio_config_base_t *deviceConfig,
         audio_patch_handle_t patchHandle)
 {
-    if (mAudioPolicyServiceClient != 0) {
+    if (mAudioPolicyServiceClient != 0 && mUid < AID_APP_START) {
         mAudioPolicyServiceClient->onRecordingConfigurationUpdate(event, clientInfo,
                 clientConfig, deviceConfig, patchHandle);
     }
diff --git a/services/mediaanalytics/MediaAnalyticsService.cpp b/services/mediaanalytics/MediaAnalyticsService.cpp
index a132e25..6d84a42 100644
--- a/services/mediaanalytics/MediaAnalyticsService.cpp
+++ b/services/mediaanalytics/MediaAnalyticsService.cpp
@@ -100,9 +100,6 @@
           mDumpProtoDefault(MediaAnalyticsItem::PROTO_V1) {
 
     ALOGD("MediaAnalyticsService created");
-    // clear our queues
-    mOpen = new List<MediaAnalyticsItem *>();
-    mFinalized = new List<MediaAnalyticsItem *>();
 
     mItemsSubmitted = 0;
     mItemsFinalized = 0;
@@ -118,26 +115,13 @@
 MediaAnalyticsService::~MediaAnalyticsService() {
         ALOGD("MediaAnalyticsService destroyed");
 
-    // clean out mOpen and mFinalized
-    while (mOpen->size() > 0) {
-        MediaAnalyticsItem * oitem = *(mOpen->begin());
-        mOpen->erase(mOpen->begin());
+    while (mItems.size() > 0) {
+        MediaAnalyticsItem * oitem = *(mItems.begin());
+        mItems.erase(mItems.begin());
         delete oitem;
         mItemsDiscarded++;
         mItemsDiscardedCount++;
     }
-    delete mOpen;
-    mOpen = NULL;
-
-    while (mFinalized->size() > 0) {
-        MediaAnalyticsItem * oitem = *(mFinalized->begin());
-        mFinalized->erase(mFinalized->begin());
-        delete oitem;
-        mItemsDiscarded++;
-        mItemsDiscardedCount++;
-    }
-    delete mFinalized;
-    mFinalized = NULL;
 }
 
 
@@ -149,9 +133,14 @@
 }
 
 // caller surrenders ownership of 'item'
-MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(MediaAnalyticsItem *item, bool forcenew) {
+MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(MediaAnalyticsItem *item, bool forcenew)
+{
+    UNUSED(forcenew);
 
-    MediaAnalyticsItem::SessionID_t id = MediaAnalyticsItem::SessionIDInvalid;
+    // fill in a sessionID if we do not yet have one
+    if (item->getSessionID() <= MediaAnalyticsItem::SessionIDNone) {
+        item->setSessionID(generateUniqueSessionID());
+    }
 
     // we control these, generally not trusting user input
     nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
@@ -164,9 +153,7 @@
     int uid_given = item->getUid();
     int pid_given = item->getPid();
 
-    // although we do make exceptions for particular client uids
-    // that we know we trust.
-    //
+    // although we do make exceptions for some trusted client uids
     bool isTrusted = false;
 
     ALOGV("caller has uid=%d, embedded uid=%d", uid, uid_given);
@@ -192,7 +179,6 @@
             break;
     }
 
-
     // Overwrite package name and version if the caller was untrusted.
     if (!isTrusted) {
       setPkgInfo(item, item->getUid(), true, true);
@@ -217,75 +203,23 @@
         return MediaAnalyticsItem::SessionIDInvalid;
     }
 
-
-    // if we have a sesisonid in the new record, look to make
+    // XXX: if we have a sessionid in the new record, look to make
     // sure it doesn't appear in the finalized list.
     // XXX: this is for security / DOS prevention.
     // may also require that we persist the unique sessionIDs
     // across boots [instead of within a single boot]
 
-
-    // match this new record up against records in the open
-    // list...
-    // if there's a match, merge them together
-    // deal with moving the old / merged record into the finalized que
-
-    bool finalizing = item->getFinalized();
-
-    Mutex::Autolock _l(mLock);
-
-    // if finalizing, we'll remove it
-    MediaAnalyticsItem *oitem = findItem(mOpen, item, finalizing | forcenew);
-    if (oitem != NULL) {
-        if (forcenew) {
-            // old one gets finalized, then we insert the new one
-            // so we'll have 2 records at the end of this.
-            // but don't finalize an empty record
-            if (oitem->count() == 0) {
-                // we're responsible for disposing of the dead record
-                delete oitem;
-                oitem = NULL;
-            } else {
-                oitem->setFinalized(true);
-                saveItem(mFinalized, oitem, 0);
-            }
-            // new record could itself be marked finalized...
-            id = item->getSessionID();
-            if (finalizing) {
-                saveItem(mFinalized, item, 0);
-                mItemsFinalized++;
-            } else {
-                saveItem(mOpen, item, 1);
-            }
-        } else {
-            // combine the records, send it to finalized if appropriate
-            oitem->merge(item);
-            id = oitem->getSessionID();
-            if (finalizing) {
-                saveItem(mFinalized, oitem, 0);
-                mItemsFinalized++;
-            }
-
-            // we're responsible for disposing of the dead record
-            delete item;
-            item = NULL;
-        }
-    } else {
-        // nothing to merge, save the new record
-        id = item->getSessionID();
-        if (finalizing) {
-            if (item->count() == 0) {
-                // drop empty records
-                delete item;
-                item = NULL;
-            } else {
-                saveItem(mFinalized, item, 0);
-                mItemsFinalized++;
-            }
-        } else {
-            saveItem(mOpen, item, 1);
-        }
+    if (item->count() == 0) {
+        // drop empty records
+        delete item;
+        item = NULL;
+        return MediaAnalyticsItem::SessionIDInvalid;
     }
+
+    // save the new record
+    MediaAnalyticsItem::SessionID_t id = item->getSessionID();
+    saveItem(item);
+    mItemsFinalized++;
     return id;
 }
 
@@ -378,6 +312,7 @@
     }
 
     Mutex::Autolock _l(mLock);
+    // mutex between insertion and dumping the contents
 
     mDumpProto = chosenProto;
 
@@ -392,9 +327,9 @@
 
     if (clear) {
         // remove everything from the finalized queue
-        while (mFinalized->size() > 0) {
-            MediaAnalyticsItem * oitem = *(mFinalized->begin());
-            mFinalized->erase(mFinalized->begin());
+        while (mItems.size() > 0) {
+            MediaAnalyticsItem * oitem = *(mItems.begin());
+            mItems.erase(mItems.begin());
             delete oitem;
             mItemsDiscarded++;
         }
@@ -408,7 +343,8 @@
 }
 
 // dump headers
-void MediaAnalyticsService::dumpHeaders(String8 &result, nsecs_t ts_since) {
+void MediaAnalyticsService::dumpHeaders(String8 &result, nsecs_t ts_since)
+{
     const size_t SIZE = 512;
     char buffer[SIZE];
 
@@ -425,7 +361,7 @@
 
     snprintf(buffer, SIZE,
         "Since Boot: Submissions: %8" PRId64
-            " Finalizations: %8" PRId64 "\n",
+            " Accepted: %8" PRId64 "\n",
         mItemsSubmitted, mItemsFinalized);
     result.append(buffer);
     snprintf(buffer, SIZE,
@@ -433,19 +369,17 @@
             " (by Count: %" PRId64 " by Expiration: %" PRId64 ")\n",
          mItemsDiscarded, mItemsDiscardedCount, mItemsDiscardedExpire);
     result.append(buffer);
-    snprintf(buffer, SIZE,
-        "Summary Sets Discarded: %" PRId64 "\n", mSetsDiscarded);
-    result.append(buffer);
     if (ts_since != 0) {
         snprintf(buffer, SIZE,
-            "Dumping Queue entries more recent than: %" PRId64 "\n",
+            "Emitting Queue entries more recent than: %" PRId64 "\n",
             (int64_t) ts_since);
         result.append(buffer);
     }
 }
 
 // the recent, detailed queues
-void MediaAnalyticsService::dumpRecent(String8 &result, nsecs_t ts_since, const char * only) {
+void MediaAnalyticsService::dumpRecent(String8 &result, nsecs_t ts_since, const char * only)
+{
     const size_t SIZE = 512;
     char buffer[SIZE];
 
@@ -456,30 +390,27 @@
     // show the recently recorded records
     snprintf(buffer, sizeof(buffer), "\nFinalized Metrics (oldest first):\n");
     result.append(buffer);
-    result.append(this->dumpQueue(mFinalized, ts_since, only));
-
-    snprintf(buffer, sizeof(buffer), "\nIn-Progress Metrics (newest first):\n");
-    result.append(buffer);
-    result.append(this->dumpQueue(mOpen, ts_since, only));
+    result.append(this->dumpQueue(ts_since, only));
 
     // show who is connected and injecting records?
     // talk about # records fed to the 'readers'
     // talk about # records we discarded, perhaps "discarded w/o reading" too
 }
+
 // caller has locked mLock...
-String8 MediaAnalyticsService::dumpQueue(List<MediaAnalyticsItem *> *theList) {
-    return dumpQueue(theList, (nsecs_t) 0, NULL);
+String8 MediaAnalyticsService::dumpQueue() {
+    return dumpQueue((nsecs_t) 0, NULL);
 }
 
-String8 MediaAnalyticsService::dumpQueue(List<MediaAnalyticsItem *> *theList, nsecs_t ts_since, const char * only) {
+String8 MediaAnalyticsService::dumpQueue(nsecs_t ts_since, const char * only) {
     String8 result;
     int slot = 0;
 
-    if (theList->empty()) {
+    if (mItems.empty()) {
             result.append("empty\n");
     } else {
-        List<MediaAnalyticsItem *>::iterator it = theList->begin();
-        for (; it != theList->end(); it++) {
+        List<MediaAnalyticsItem *>::iterator it = mItems.begin();
+        for (; it != mItems.end(); it++) {
             nsecs_t when = (*it)->getTimestamp();
             if (when < ts_since) {
                 continue;
@@ -500,35 +431,25 @@
 
 //
 // Our Cheap in-core, non-persistent records management.
-// XXX: rewrite this to manage persistence, etc.
 
 // insert appropriately into queue
-// caller should hold mLock
-void MediaAnalyticsService::saveItem(List<MediaAnalyticsItem *> *l, MediaAnalyticsItem * item, int front) {
+void MediaAnalyticsService::saveItem(MediaAnalyticsItem * item)
+{
 
-    if (front)  {
-        // for non-finalized stuff, since we expect to reference it again soon,
-        // make it quicker to find (nearer the front of our list)
-        l->push_front(item);
-    } else {
-        // for finalized records, which we want to dump 'in sequence order'
-        l->push_back(item);
-    }
+    Mutex::Autolock _l(mLock);
+    // mutex between insertion and dumping the contents
 
-    // our reclaim process is for oldest-first queues
-    if (front) {
-        return;
-    }
-
+    // we want to dump 'in FIFO order', so insert at the end
+    mItems.push_back(item);
 
     // keep removing old records the front until we're in-bounds (count)
     if (mMaxRecords > 0) {
-        while (l->size() > (size_t) mMaxRecords) {
-            MediaAnalyticsItem * oitem = *(l->begin());
+        while (mItems.size() > (size_t) mMaxRecords) {
+            MediaAnalyticsItem * oitem = *(mItems.begin());
             if (oitem == item) {
                 break;
             }
-            l->erase(l->begin());
+            mItems.erase(mItems.begin());
             delete oitem;
             mItemsDiscarded++;
             mItemsDiscardedCount++;
@@ -536,10 +457,11 @@
     }
 
     // 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
     if (mMaxRecordAgeNs > 0) {
         nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
-        while (l->size() > 0) {
-            MediaAnalyticsItem * oitem = *(l->begin());
+        while (mItems.size() > 0) {
+            MediaAnalyticsItem * oitem = *(mItems.begin());
             nsecs_t when = oitem->getTimestamp();
             if (oitem == item) {
                 break;
@@ -549,7 +471,7 @@
                 // this (and the rest) are recent enough to keep
                 break;
             }
-            l->erase(l->begin());
+            mItems.erase(mItems.begin());
             delete oitem;
             mItemsDiscarded++;
             mItemsDiscardedExpire++;
@@ -557,79 +479,6 @@
     }
 }
 
-// are they alike enough that nitem can be folded into oitem?
-static bool compatibleItems(MediaAnalyticsItem * oitem, MediaAnalyticsItem * nitem) {
-
-    // general safety
-    if (nitem->getUid() != oitem->getUid()) {
-        return false;
-    }
-    if (nitem->getPid() != oitem->getPid()) {
-        return false;
-    }
-
-    // key -- needs to match
-    if (nitem->getKey() == oitem->getKey()) {
-        // still in the game.
-    } else {
-        return false;
-    }
-
-    // session id -- empty field in new is allowed
-    MediaAnalyticsItem::SessionID_t osession = oitem->getSessionID();
-    MediaAnalyticsItem::SessionID_t nsession = nitem->getSessionID();
-    if (nsession != osession) {
-        // incoming '0' matches value in osession
-        if (nsession != 0) {
-            return false;
-        }
-    }
-
-    return true;
-}
-
-// find the incomplete record that this will overlay
-// caller should hold mLock
-MediaAnalyticsItem *MediaAnalyticsService::findItem(List<MediaAnalyticsItem*> *theList, MediaAnalyticsItem *nitem, bool removeit) {
-    if (nitem == NULL) {
-        return NULL;
-    }
-
-    MediaAnalyticsItem *item = NULL;
-
-    for (List<MediaAnalyticsItem *>::iterator it = theList->begin();
-        it != theList->end(); it++) {
-        MediaAnalyticsItem *tmp = (*it);
-
-        if (!compatibleItems(tmp, nitem)) {
-            continue;
-        }
-
-        // we match! this is the one I want.
-        if (removeit) {
-            theList->erase(it);
-        }
-        item = tmp;
-        break;
-    }
-    return item;
-}
-
-
-// delete the indicated record
-// caller should hold mLock
-void MediaAnalyticsService::deleteItem(List<MediaAnalyticsItem *> *l, MediaAnalyticsItem *item) {
-
-    for (List<MediaAnalyticsItem *>::iterator it = l->begin();
-        it != l->end(); it++) {
-        if ((*it)->getSessionID() != item->getSessionID())
-            continue;
-        delete *it;
-        l->erase(it);
-        break;
-    }
-}
-
 static std::string allowedKeys[] =
 {
     "audiorecord",
@@ -676,7 +525,9 @@
 #define PKG_EXPIRATION_NS (30*60*1000000000ll)   // 30 minutes, in nsecs
 
 // give me the package name, perhaps going to find it
-void MediaAnalyticsService::setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion) {
+// manages its own mutex operations internally
+void MediaAnalyticsService::setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion)
+{
     ALOGV("asking for packagename to go with uid=%d", uid);
 
     if (!setName && !setVersion) {
@@ -686,22 +537,26 @@
 
     nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
     struct UidToPkgMap mapping;
-    mapping.uid = (-1);
+    mapping.uid = (uid_t)(-1);
 
-    ssize_t i = mPkgMappings.indexOfKey(uid);
-    if (i >= 0) {
-        mapping = mPkgMappings.valueAt(i);
-        ALOGV("Expiration? uid %d expiration %" PRId64 " now %" PRId64,
-              uid, mapping.expiration, now);
-        if (mapping.expiration < now) {
-            // purge our current entry and re-query
-            ALOGV("entry for uid %d expired, now= %" PRId64 "", uid, now);
-            mPkgMappings.removeItemsAt(i, 1);
-            // could cheat and use a goto back to the top of the routine.
-            // a good compiler should recognize the local tail recursion...
-            return setPkgInfo(item, uid, setName, setVersion);
+    {
+        Mutex::Autolock _l(mLock_mappings);
+        int i = mPkgMappings.indexOfKey(uid);
+        if (i >= 0) {
+            mapping = mPkgMappings.valueAt(i);
+            ALOGV("Expiration? uid %d expiration %" PRId64 " now %" PRId64,
+                  uid, mapping.expiration, now);
+            if (mapping.expiration <= now) {
+                // purge the stale entry and fall into re-fetching
+                ALOGV("entry for uid %d expired, now= %" PRId64 "", uid, now);
+                mPkgMappings.removeItemsAt(i);
+                mapping.uid = (uid_t)(-1);
+            }
         }
-    } else {
+    }
+
+    // if we did not find it
+    if (mapping.uid == (uid_t)(-1)) {
         std::string pkg;
         std::string installer = "";
         int64_t versionCode = 0;
@@ -711,7 +566,7 @@
             pkg = pw->pw_name;
         }
 
-        // find the proper value -- should we cache this binder??
+        // find the proper value
 
         sp<IBinder> binder = NULL;
         sp<IServiceManager> sm = defaultServiceManager();
diff --git a/services/mediaanalytics/MediaAnalyticsService.h b/services/mediaanalytics/MediaAnalyticsService.h
index 484339c..b3c902a 100644
--- a/services/mediaanalytics/MediaAnalyticsService.h
+++ b/services/mediaanalytics/MediaAnalyticsService.h
@@ -53,7 +53,6 @@
     int64_t mItemsDiscarded;
     int64_t mItemsDiscardedExpire;
     int64_t mItemsDiscardedCount;
-    int64_t mSetsDiscarded;
     MediaAnalyticsItem::SessionID_t mLastSessionID;
 
     // partitioned a bit so we don't over serialize
@@ -76,25 +75,15 @@
     bool contentValid(MediaAnalyticsItem *item, bool isTrusted);
     bool rateLimited(MediaAnalyticsItem *);
 
-    // the ones that are still open
-    // (newest at front) since we keep looking for them
-    List<MediaAnalyticsItem *> *mOpen;
-    // the ones we've finalized
     // (oldest at front) so it prints nicely for dumpsys
-    List<MediaAnalyticsItem *> *mFinalized;
-    // searching within these queues: queue, key
-    MediaAnalyticsItem *findItem(List<MediaAnalyticsItem *> *,
-                                     MediaAnalyticsItem *, bool removeit);
-
-    void saveItem(MediaAnalyticsItem);
-    void saveItem(List<MediaAnalyticsItem *> *, MediaAnalyticsItem *, int);
-    void deleteItem(List<MediaAnalyticsItem *> *, MediaAnalyticsItem *);
+    List<MediaAnalyticsItem *> mItems;
+    void saveItem(MediaAnalyticsItem *);
 
     // support for generating output
     int mDumpProto;
     int mDumpProtoDefault;
-    String8 dumpQueue(List<MediaAnalyticsItem*> *);
-    String8 dumpQueue(List<MediaAnalyticsItem*> *, nsecs_t, const char *only);
+    String8 dumpQueue();
+    String8 dumpQueue(nsecs_t, const char *only);
 
     void dumpHeaders(String8 &result, nsecs_t ts_since);
     void dumpSummaries(String8 &result, nsecs_t ts_since, const char * only);