Merge "Wait for iref box if the heic file has Exif data"
diff --git a/cmds/screenrecord/Android.bp b/cmds/screenrecord/Android.bp
new file mode 100644
index 0000000..86476cd
--- /dev/null
+++ b/cmds/screenrecord/Android.bp
@@ -0,0 +1,55 @@
+// Copyright 2013 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.
+
+cc_binary {
+    name: "screenrecord",
+
+    srcs: [
+        "screenrecord.cpp",
+        "EglWindow.cpp",
+        "FrameOutput.cpp",
+        "TextRenderer.cpp",
+        "Overlay.cpp",
+        "Program.cpp",
+    ],
+
+    shared_libs: [
+        "libstagefright",
+        "libmedia",
+        "libmedia_omx",
+        "libutils",
+        "libbinder",
+        "libstagefright_foundation",
+        "libjpeg",
+        "libui",
+        "libgui",
+        "libcutils",
+        "liblog",
+        "libEGL",
+        "libGLESv2",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright",
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/native/include/media/openmax",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-Wno-multichar",
+        //"-UNDEBUG",
+    ]
+}
diff --git a/cmds/screenrecord/Android.mk b/cmds/screenrecord/Android.mk
deleted file mode 100644
index 5e83ed6..0000000
--- a/cmds/screenrecord/Android.mk
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright 2013 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-	screenrecord.cpp \
-	EglWindow.cpp \
-	FrameOutput.cpp \
-	TextRenderer.cpp \
-	Overlay.cpp \
-	Program.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-	libstagefright libmedia libmedia_omx libutils libbinder libstagefright_foundation \
-	libjpeg libui libgui libcutils liblog libEGL libGLESv2
-
-LOCAL_C_INCLUDES := \
-	frameworks/av/media/libstagefright \
-	frameworks/av/media/libstagefright/include \
-	frameworks/native/include/media/openmax \
-	external/jpeg
-
-LOCAL_CFLAGS := -Werror -Wall
-LOCAL_CFLAGS += -Wno-multichar
-#LOCAL_CFLAGS += -UNDEBUG
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE:= screenrecord
-
-include $(BUILD_EXECUTABLE)
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 34a9a40..bf36be0 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -46,6 +46,7 @@
 #include <media/stagefright/JPEGSource.h>
 #include <media/stagefright/InterfaceUtils.h>
 #include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaCodecConstants.h>
 #include <media/stagefright/MediaCodecList.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
@@ -628,7 +629,7 @@
     fprintf(stderr, "       -l(ist) components\n");
     fprintf(stderr, "       -m max-number-of-frames-to-decode in each pass\n");
     fprintf(stderr, "       -b bug to reproduce\n");
-    fprintf(stderr, "       -p(rofiles) dump decoder profiles supported\n");
+    fprintf(stderr, "       -i(nfo) dump codec info (profiles and color formats supported, details)\n");
     fprintf(stderr, "       -t(humbnail) extract video thumbnail or album art\n");
     fprintf(stderr, "       -s(oftware) prefer software codec\n");
     fprintf(stderr, "       -r(hardware) force to use hardware codec\n");
@@ -646,55 +647,131 @@
     fprintf(stderr, "       -v be more verbose\n");
 }
 
-static void dumpCodecProfiles(bool queryDecoders) {
-    const char *kMimeTypes[] = {
-        MEDIA_MIMETYPE_VIDEO_AVC, MEDIA_MIMETYPE_VIDEO_MPEG4,
-        MEDIA_MIMETYPE_VIDEO_H263, MEDIA_MIMETYPE_AUDIO_AAC,
-        MEDIA_MIMETYPE_AUDIO_AMR_NB, MEDIA_MIMETYPE_AUDIO_AMR_WB,
-        MEDIA_MIMETYPE_AUDIO_MPEG, MEDIA_MIMETYPE_AUDIO_G711_MLAW,
-        MEDIA_MIMETYPE_AUDIO_G711_ALAW, MEDIA_MIMETYPE_AUDIO_VORBIS,
-        MEDIA_MIMETYPE_VIDEO_VP8, MEDIA_MIMETYPE_VIDEO_VP9,
-        MEDIA_MIMETYPE_VIDEO_DOLBY_VISION, MEDIA_MIMETYPE_VIDEO_HEVC,
-        MEDIA_MIMETYPE_AUDIO_EAC3, MEDIA_MIMETYPE_AUDIO_AC4,
-        MEDIA_MIMETYPE_VIDEO_AV1
-    };
-
-    const char *codecType = queryDecoders? "decoder" : "encoder";
-    printf("%s profiles:\n", codecType);
+static void dumpCodecDetails(bool queryDecoders) {
+    const char *codecType = queryDecoders? "Decoder" : "Encoder";
+    printf("\n%s infos by media types:\n"
+           "=============================\n", codecType);
 
     sp<IMediaCodecList> list = MediaCodecList::getInstance();
     size_t numCodecs = list->countCodecs();
 
-    for (size_t k = 0; k < sizeof(kMimeTypes) / sizeof(kMimeTypes[0]); ++k) {
-        printf("type '%s':\n", kMimeTypes[k]);
+    // gather all media types supported by codec class, and link to codecs that support them
+    KeyedVector<AString, Vector<sp<MediaCodecInfo>>> allMediaTypes;
+    for (size_t codec_ix = 0; codec_ix < numCodecs; ++codec_ix) {
+        sp<MediaCodecInfo> info = list->getCodecInfo(codec_ix);
+        if (info->isEncoder() == !queryDecoders) {
+            Vector<AString> supportedMediaTypes;
+            info->getSupportedMediaTypes(&supportedMediaTypes);
+            if (!supportedMediaTypes.size()) {
+                printf("warning: %s does not support any media types\n",
+                        info->getCodecName());
+            } else {
+                for (const AString &mediaType : supportedMediaTypes) {
+                    if (allMediaTypes.indexOfKey(mediaType) < 0) {
+                        allMediaTypes.add(mediaType, Vector<sp<MediaCodecInfo>>());
+                    }
+                    allMediaTypes.editValueFor(mediaType).add(info);
+                }
+            }
+        }
+    }
 
-        for (size_t index = 0; index < numCodecs; ++index) {
-            sp<MediaCodecInfo> info = list->getCodecInfo(index);
-            if (info == NULL || info->isEncoder() != !queryDecoders) {
-                continue;
-            }
-            sp<MediaCodecInfo::Capabilities> caps = info->getCapabilitiesFor(kMimeTypes[k]);
+    KeyedVector<AString, bool> visitedCodecs;
+    for (size_t type_ix = 0; type_ix < allMediaTypes.size(); ++type_ix) {
+        const AString &mediaType = allMediaTypes.keyAt(type_ix);
+        printf("\nMedia type '%s':\n", mediaType.c_str());
+
+        for (const sp<MediaCodecInfo> &info : allMediaTypes.valueAt(type_ix)) {
+            sp<MediaCodecInfo::Capabilities> caps = info->getCapabilitiesFor(mediaType.c_str());
             if (caps == NULL) {
+                printf("warning: %s does not have capabilities for type %s\n",
+                        info->getCodecName(), mediaType.c_str());
                 continue;
             }
-            printf("  %s '%s' supports ",
+            printf("  %s \"%s\" supports\n",
                        codecType, info->getCodecName());
 
-            Vector<MediaCodecInfo::ProfileLevel> profileLevels;
-            caps->getSupportedProfileLevels(&profileLevels);
-            if (profileLevels.size() == 0) {
-                printf("NOTHING.\n");
-                continue;
+            auto printList = [](const char *type, const Vector<AString> &values){
+                printf("    %s: [", type);
+                for (size_t j = 0; j < values.size(); ++j) {
+                    printf("\n      %s%s", values[j].c_str(),
+                            j == values.size() - 1 ? " " : ",");
+                }
+                printf("]\n");
+            };
+
+            if (visitedCodecs.indexOfKey(info->getCodecName()) < 0) {
+                visitedCodecs.add(info->getCodecName(), true);
+                {
+                    Vector<AString> aliases;
+                    info->getAliases(&aliases);
+                    // quote alias
+                    for (AString &alias : aliases) {
+                        alias.insert("\"", 1, 0);
+                        alias.append('"');
+                    }
+                    printList("aliases", aliases);
+                }
+                {
+                    uint32_t attrs = info->getAttributes();
+                    Vector<AString> list;
+                    list.add(AStringPrintf("encoder: %d", !!(attrs & MediaCodecInfo::kFlagIsEncoder)));
+                    list.add(AStringPrintf("vendor: %d", !!(attrs & MediaCodecInfo::kFlagIsVendor)));
+                    list.add(AStringPrintf("software-only: %d", !!(attrs & MediaCodecInfo::kFlagIsSoftwareOnly)));
+                    list.add(AStringPrintf("hw-accelerated: %d", !!(attrs & MediaCodecInfo::kFlagIsHardwareAccelerated)));
+                    printList(AStringPrintf("attributes: %#x", attrs).c_str(), list);
+                }
+
+                printf("    owner: \"%s\"\n", info->getOwnerName());
+                printf("    rank: %u\n", info->getRank());
+            } else {
+                printf("    aliases, attributes, owner, rank: see above\n");
             }
 
-            for (size_t j = 0; j < profileLevels.size(); ++j) {
-                const MediaCodecInfo::ProfileLevel &profileLevel = profileLevels[j];
+            {
+                Vector<AString> list;
+                Vector<MediaCodecInfo::ProfileLevel> profileLevels;
+                caps->getSupportedProfileLevels(&profileLevels);
+                for (const MediaCodecInfo::ProfileLevel &pl : profileLevels) {
+                    const char *niceProfile =
+                        mediaType.equalsIgnoreCase(MIMETYPE_AUDIO_AAC)   ? asString_AACObject(pl.mProfile) :
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_MPEG2) ? asString_MPEG2Profile(pl.mProfile) :
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_H263)  ? asString_H263Profile(pl.mProfile) :
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_MPEG4) ? asString_MPEG4Profile(pl.mProfile) :
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_AVC)   ? asString_AVCProfile(pl.mProfile) :
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_VP8)   ? asString_VP8Profile(pl.mProfile) :
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_HEVC)  ? asString_HEVCProfile(pl.mProfile) :
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_VP9)   ? asString_VP9Profile(pl.mProfile) :
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_AV1)   ? asString_AV1Profile(pl.mProfile) :"??";
+                    const char *niceLevel =
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_MPEG2) ? asString_MPEG2Level(pl.mLevel) :
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_H263)  ? asString_H263Level(pl.mLevel) :
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_MPEG4) ? asString_MPEG4Level(pl.mLevel) :
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_AVC)   ? asString_AVCLevel(pl.mLevel) :
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_VP8)   ? asString_VP8Level(pl.mLevel) :
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_HEVC)  ? asString_HEVCTierLevel(pl.mLevel) :
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_VP9)   ? asString_VP9Level(pl.mLevel) :
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_AV1)   ? asString_AV1Level(pl.mLevel) :
+                        "??";
 
-                printf("%s%u/%u", j > 0 ? ", " : "",
-                        profileLevel.mProfile, profileLevel.mLevel);
+                    list.add(AStringPrintf("% 5u/% 5u (%s/%s)",
+                            pl.mProfile, pl.mLevel, niceProfile, niceLevel));
+                }
+                printList("profile/levels", list);
             }
 
-            printf("\n");
+            {
+                Vector<AString> list;
+                Vector<uint32_t> colors;
+                caps->getSupportedColorFormats(&colors);
+                for (uint32_t color : colors) {
+                    list.add(AStringPrintf("%#x (%s)", color,
+                            asString_ColorFormat((int32_t)color)));
+                }
+                printList("colors", list);
+            }
+
+            printf("    details: %s\n", caps->getDetails()->debugString(6).c_str());
         }
     }
 }
@@ -704,7 +781,7 @@
 
     bool audioOnly = false;
     bool listComponents = false;
-    bool dumpProfiles = false;
+    bool dumpCodecInfo = false;
     bool extractThumbnail = false;
     bool seekTest = false;
     bool useSurfaceAlloc = false;
@@ -724,7 +801,7 @@
     sp<android::ALooper> looper;
 
     int res;
-    while ((res = getopt(argc, argv, "vhaqn:lm:b:ptsrow:kN:xSTd:D:")) >= 0) {
+    while ((res = getopt(argc, argv, "vhaqn:lm:b:itsrow:kN:xSTd:D:")) >= 0) {
         switch (res) {
             case 'a':
             {
@@ -794,9 +871,9 @@
                 break;
             }
 
-            case 'p':
+            case 'i':
             {
-                dumpProfiles = true;
+                dumpCodecInfo = true;
                 break;
             }
 
@@ -937,9 +1014,9 @@
         return 0;
     }
 
-    if (dumpProfiles) {
-        dumpCodecProfiles(true /* queryDecoders */);
-        dumpCodecProfiles(false /* queryDecoders */);
+    if (dumpCodecInfo) {
+        dumpCodecDetails(true /* queryDecoders */);
+        dumpCodecDetails(false /* queryDecoders */);
     }
 
     if (listComponents) {
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index 480c7cd..5888af0 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -168,7 +168,7 @@
     case OfflineLicenseState::USABLE:
         return DrmPlugin::kOfflineLicenseStateUsable;
     case OfflineLicenseState::INACTIVE:
-        return DrmPlugin::kOfflineLicenseStateInactive;
+        return DrmPlugin::kOfflineLicenseStateReleased;
     default:
         return DrmPlugin::kOfflineLicenseStateUnknown;
     }
@@ -586,51 +586,57 @@
     return Void();
 }
 
-bool DrmHal::matchMimeTypeAndSecurityLevel(sp<IDrmFactory> &factory,
-                                           const uint8_t uuid[16],
-                                           const String8 &mimeType,
-                                           DrmPlugin::SecurityLevel level) {
-    if (mimeType == "") {
-        return true;
-    } else if (!factory->isContentTypeSupported(mimeType.string())) {
-        return false;
+status_t DrmHal::matchMimeTypeAndSecurityLevel(const sp<IDrmFactory> &factory,
+                                               const uint8_t uuid[16],
+                                               const String8 &mimeType,
+                                               DrmPlugin::SecurityLevel level,
+                                               bool *isSupported) {
+    *isSupported = false;
+
+    // handle default value cases
+    if (level == DrmPlugin::kSecurityLevelUnknown) {
+        if (mimeType == "") {
+            // isCryptoSchemeSupported(uuid)
+            *isSupported = true;
+        } else {
+            // isCryptoSchemeSupported(uuid, mimeType)
+            *isSupported = factory->isContentTypeSupported(mimeType.string());
+        }
+        return OK;
+    } else if (mimeType == "") {
+        return BAD_VALUE;
     }
 
-    if (level == DrmPlugin::kSecurityLevelUnknown) {
-        return true;
+    sp<drm::V1_2::IDrmFactory> factoryV1_2 = drm::V1_2::IDrmFactory::castFrom(factory);
+    if (factoryV1_2 == NULL) {
+        return ERROR_UNSUPPORTED;
     } else {
-        sp<drm::V1_2::IDrmFactory> factoryV1_2 = drm::V1_2::IDrmFactory::castFrom(factory);
-        if (factoryV1_2 == NULL) {
-            return true;
-        } else if (factoryV1_2->isCryptoSchemeSupported_1_2(uuid,
-                        mimeType.string(), toHidlSecurityLevel(level))) {
-            return true;
-        }
+        *isSupported = factoryV1_2->isCryptoSchemeSupported_1_2(uuid,
+                mimeType.string(), toHidlSecurityLevel(level));
+        return OK;
     }
-    return false;
 }
 
-bool DrmHal::isCryptoSchemeSupported(const uint8_t uuid[16],
-                                     const String8 &mimeType,
-                                     DrmPlugin::SecurityLevel level) {
+status_t DrmHal::isCryptoSchemeSupported(const uint8_t uuid[16],
+                                         const String8 &mimeType,
+                                         DrmPlugin::SecurityLevel level,
+                                         bool *isSupported) {
     Mutex::Autolock autoLock(mLock);
-
-    for (size_t i = 0; i < mFactories.size(); i++) {
-        sp<IDrmFactory> factory = mFactories[i];
-        if (factory->isCryptoSchemeSupported(uuid)) {
-            if (matchMimeTypeAndSecurityLevel(factory, uuid, mimeType, level)) {
-                return true;
-            }
+    *isSupported = false;
+    for (ssize_t i = mFactories.size() - 1; i >= 0; i--) {
+        if (mFactories[i]->isCryptoSchemeSupported(uuid)) {
+            return matchMimeTypeAndSecurityLevel(mFactories[i],
+                    uuid, mimeType, level, isSupported);
         }
     }
-    return false;
+    return OK;
 }
 
 status_t DrmHal::createPlugin(const uint8_t uuid[16],
         const String8& appPackageName) {
     Mutex::Autolock autoLock(mLock);
 
-    for (size_t i = mFactories.size() - 1; i >= 0; i--) {
+    for (ssize_t i = mFactories.size() - 1; i >= 0; i--) {
         if (mFactories[i]->isCryptoSchemeSupported(uuid)) {
             auto plugin = makeDrmPlugin(mFactories[i], uuid, appPackageName);
             if (plugin != NULL) {
@@ -1213,7 +1219,7 @@
     }
 
     if (mPluginV1_2 == NULL) {
-        return ERROR_DRM_CANNOT_HANDLE;
+        return ERROR_UNSUPPORTED;
     }
 
     status_t err = UNKNOWN_ERROR;
@@ -1238,7 +1244,7 @@
     }
 
     if (mPluginV1_2 == NULL) {
-        return ERROR_DRM_CANNOT_HANDLE;
+        return ERROR_UNSUPPORTED;
     }
 
     Return<Status> status = mPluginV1_2->removeOfflineLicense(toHidlVec(keySetId));
@@ -1254,7 +1260,7 @@
     }
 
     if (mPluginV1_2 == NULL) {
-        return ERROR_DRM_CANNOT_HANDLE;
+        return ERROR_UNSUPPORTED;
     }
     *licenseState = DrmPlugin::kOfflineLicenseStateUnknown;
 
@@ -1550,22 +1556,22 @@
 
 void DrmHal::reportFrameworkMetrics() const
 {
-    MediaAnalyticsItem item("mediadrm");
-    item.generateSessionID();
-    item.setPkgName(mMetrics.GetAppPackageName().c_str());
+    std::unique_ptr<MediaAnalyticsItem> item(MediaAnalyticsItem::create("mediadrm"));
+    item->generateSessionID();
+    item->setPkgName(mMetrics.GetAppPackageName().c_str());
     String8 vendor;
     String8 description;
     status_t result = getPropertyStringInternal(String8("vendor"), vendor);
     if (result != OK) {
         ALOGE("Failed to get vendor from drm plugin: %d", result);
     } else {
-        item.setCString("vendor", vendor.c_str());
+        item->setCString("vendor", vendor.c_str());
     }
     result = getPropertyStringInternal(String8("description"), description);
     if (result != OK) {
         ALOGE("Failed to get description from drm plugin: %d", result);
     } else {
-        item.setCString("description", description.c_str());
+        item->setCString("description", description.c_str());
     }
 
     std::string serializedMetrics;
@@ -1576,9 +1582,9 @@
     std::string b64EncodedMetrics = toBase64StringNoPad(serializedMetrics.data(),
                                                         serializedMetrics.size());
     if (!b64EncodedMetrics.empty()) {
-        item.setCString("serialized_metrics", b64EncodedMetrics.c_str());
+        item->setCString("serialized_metrics", b64EncodedMetrics.c_str());
     }
-    if (!item.selfrecord()) {
+    if (!item->selfrecord()) {
         ALOGE("Failed to self record framework metrics");
     }
 }
diff --git a/drm/libmediadrm/IDrm.cpp b/drm/libmediadrm/IDrm.cpp
index 0f34315..51274d1 100644
--- a/drm/libmediadrm/IDrm.cpp
+++ b/drm/libmediadrm/IDrm.cpp
@@ -83,8 +83,8 @@
         return reply.readInt32();
     }
 
-    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType,
-            DrmPlugin::SecurityLevel level) {
+    virtual status_t isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType,
+            DrmPlugin::SecurityLevel level, bool *isSupported) {
         Parcel data, reply;
         data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
         data.write(uuid, 16);
@@ -94,10 +94,11 @@
         status_t status = remote()->transact(IS_CRYPTO_SUPPORTED, data, &reply);
         if (status != OK) {
             ALOGE("isCryptoSchemeSupported: binder call failed: %d", status);
-            return false;
+            return status;
         }
+        *isSupported = static_cast<bool>(reply.readInt32());
 
-        return reply.readInt32() != 0;
+        return reply.readInt32();
     }
 
     virtual status_t createPlugin(const uint8_t uuid[16],
@@ -773,7 +774,10 @@
             String8 mimeType = data.readString8();
             DrmPlugin::SecurityLevel level =
                     static_cast<DrmPlugin::SecurityLevel>(data.readInt32());
-            reply->writeInt32(isCryptoSchemeSupported(uuid, mimeType, level));
+            bool isSupported = false;
+            status_t result = isCryptoSchemeSupported(uuid, mimeType, level, &isSupported);
+            reply->writeInt32(isSupported);
+            reply->writeInt32(result);
             return OK;
         }
 
diff --git a/drm/libmediadrm/PluginMetricsReporting.cpp b/drm/libmediadrm/PluginMetricsReporting.cpp
index 5cb48bf..8cd6f96 100644
--- a/drm/libmediadrm/PluginMetricsReporting.cpp
+++ b/drm/libmediadrm/PluginMetricsReporting.cpp
@@ -34,17 +34,17 @@
 status_t reportVendorMetrics(const std::string& metrics,
                              const String8& name,
                              const String8& appPackageName) {
-    MediaAnalyticsItem analyticsItem(name.c_str());
-    analyticsItem.generateSessionID();
+    std::unique_ptr<MediaAnalyticsItem> analyticsItem(MediaAnalyticsItem::create(name.c_str()));
+    analyticsItem->generateSessionID();
 
     std::string app_package_name(appPackageName.c_str(), appPackageName.size());
-    analyticsItem.setPkgName(app_package_name);
+    analyticsItem->setPkgName(app_package_name);
     if (metrics.size() > 0) {
-        analyticsItem.setCString(kSerializedMetricsField, metrics.c_str());
+        analyticsItem->setCString(kSerializedMetricsField, metrics.c_str());
     }
 
-    if (!analyticsItem.selfrecord()) {
-      ALOGE("selfrecord() returned false. sessioId %" PRId64, analyticsItem.getSessionID());
+    if (!analyticsItem->selfrecord()) {
+      ALOGE("selfrecord() returned false. sessioId %" PRId64, analyticsItem->getSessionID());
     }
 
     return OK;
diff --git a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
index 1558e8b..27bd631 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
+++ b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
@@ -65,7 +65,20 @@
     *plugin = new ClearKeyCasPlugin(appData, callback);
     return OK;
 }
-///////////////////////////////////////////////////////////////////////////////
+
+status_t ClearKeyCasFactory::createPlugin(
+        int32_t CA_system_id,
+        void *appData,
+        CasPluginCallbackExt callback,
+        CasPlugin **plugin) {
+    if (!isSystemIdSupported(CA_system_id)) {
+        return BAD_VALUE;
+    }
+
+    *plugin = new ClearKeyCasPlugin(appData, callback);
+    return OK;
+}
+////////////////////////////////////////////////////////////////////////////////
 bool ClearKeyDescramblerFactory::isSystemIdSupported(
         int32_t CA_system_id) const {
     return CA_system_id == sClearKeySystemId;
@@ -88,6 +101,12 @@
     ALOGV("CTOR");
 }
 
+ClearKeyCasPlugin::ClearKeyCasPlugin(
+        void *appData, CasPluginCallbackExt callback)
+    : mCallbackExt(callback), mAppData(appData) {
+    ALOGV("CTOR");
+}
+
 ClearKeyCasPlugin::~ClearKeyCasPlugin() {
     ALOGV("DTOR");
     ClearKeySessionLibrary::get()->destroyPlugin(this);
@@ -167,11 +186,30 @@
     // Echo the received event to the callback.
     // Clear key plugin doesn't use any event, echo'ing for testing only.
     if (mCallback != NULL) {
-        mCallback((void*)mAppData, event, arg, (uint8_t*)eventData.data(), eventData.size());
+        mCallback((void*)mAppData, event, arg, (uint8_t*)eventData.data(),
+                    eventData.size());
+    } else if (mCallbackExt != NULL) {
+        mCallbackExt((void*)mAppData, event, arg, (uint8_t*)eventData.data(),
+                    eventData.size(), NULL);
     }
     return OK;
 }
 
+status_t ClearKeyCasPlugin::sendSessionEvent(
+        const CasSessionId &sessionId, int32_t event,
+        int arg, const CasData &eventData) {
+    ALOGV("sendSessionEvent: sessionId=%s, event=%d, arg=%d",
+          sessionIdToString(sessionId).string(), event, arg);
+    // Echo the received event to the callback.
+    // Clear key plugin doesn't use any event, echo'ing for testing only.
+    if (mCallbackExt != NULL) {
+        mCallbackExt((void*)mAppData, event, arg, (uint8_t*)eventData.data(),
+                    eventData.size(), &sessionId);
+    }
+
+    return OK;
+}
+
 status_t ClearKeyCasPlugin::provision(const String8 &str) {
     ALOGV("provision: provisionString=%s", str.string());
     Mutex::Autolock lock(mKeyFetcherLock);
diff --git a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h
index 389e172..f48d5b1 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h
+++ b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h
@@ -47,6 +47,11 @@
             void *appData,
             CasPluginCallback callback,
             CasPlugin **plugin) override;
+    virtual status_t createPlugin(
+            int32_t CA_system_id,
+            void *appData,
+            CasPluginCallbackExt callback,
+            CasPlugin **plugin) override;
 };
 
 class ClearKeyDescramblerFactory : public DescramblerFactory {
@@ -63,6 +68,7 @@
 class ClearKeyCasPlugin : public CasPlugin {
 public:
     ClearKeyCasPlugin(void *appData, CasPluginCallback callback);
+    ClearKeyCasPlugin(void *appData, CasPluginCallbackExt callback);
     virtual ~ClearKeyCasPlugin();
 
     virtual status_t setPrivateData(
@@ -85,6 +91,10 @@
     virtual status_t sendEvent(
             int32_t event, int32_t arg, const CasData &eventData) override;
 
+    virtual status_t sendSessionEvent(
+            const CasSessionId &sessionId,
+            int32_t event, int32_t arg, const CasData &eventData) override;
+
     virtual status_t provision(const String8 &str) override;
 
     virtual status_t refreshEntitlements(
@@ -94,6 +104,7 @@
     Mutex mKeyFetcherLock;
     std::unique_ptr<KeyFetcher> mKeyFetcher;
     CasPluginCallback mCallback;
+    CasPluginCallbackExt mCallbackExt;
     void* mAppData;
 };
 
diff --git a/drm/mediacas/plugins/mock/MockCasPlugin.cpp b/drm/mediacas/plugins/mock/MockCasPlugin.cpp
index 8404a83..2964791 100644
--- a/drm/mediacas/plugins/mock/MockCasPlugin.cpp
+++ b/drm/mediacas/plugins/mock/MockCasPlugin.cpp
@@ -60,6 +60,19 @@
     return OK;
 }
 
+status_t MockCasFactory::createPlugin(
+        int32_t CA_system_id,
+        void* /*appData*/,
+        CasPluginCallbackExt /*callback*/,
+        CasPlugin **plugin) {
+    if (!isSystemIdSupported(CA_system_id)) {
+        return BAD_VALUE;
+    }
+
+    *plugin = new MockCasPlugin();
+    return OK;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 bool MockDescramblerFactory::isSystemIdSupported(int32_t CA_system_id) const {
@@ -170,6 +183,16 @@
     return OK;
 }
 
+status_t MockCasPlugin::sendSessionEvent(
+        const CasSessionId &sessionId, int32_t event,
+        int /*arg*/, const CasData& /*eventData*/) {
+    ALOGV("sendSessionEvent: sessionId=%s, event=%d",
+          arrayToString(sessionId).string(), event);
+    Mutex::Autolock lock(mLock);
+
+    return OK;
+}
+
 status_t MockCasPlugin::provision(const String8 &str) {
     ALOGV("provision: provisionString=%s", str.string());
     Mutex::Autolock lock(mLock);
diff --git a/drm/mediacas/plugins/mock/MockCasPlugin.h b/drm/mediacas/plugins/mock/MockCasPlugin.h
index 8106990..74b540c 100644
--- a/drm/mediacas/plugins/mock/MockCasPlugin.h
+++ b/drm/mediacas/plugins/mock/MockCasPlugin.h
@@ -42,6 +42,11 @@
             void *appData,
             CasPluginCallback callback,
             CasPlugin **plugin) override;
+    virtual status_t createPlugin(
+            int32_t CA_system_id,
+            void *appData,
+            CasPluginCallbackExt callback,
+            CasPlugin **plugin) override;
 };
 
 class MockDescramblerFactory : public DescramblerFactory {
@@ -80,7 +85,11 @@
     virtual status_t sendEvent(
             int32_t event, int32_t arg, const CasData &eventData) override;
 
-    virtual status_t provision(const String8 &str) override;
+    virtual status_t sendSessionEvent(
+            const CasSessionId &sessionId,
+            int32_t event, int32_t arg, const CasData &eventData) override;
+
+     virtual status_t provision(const String8 &str) override;
 
     virtual status_t refreshEntitlements(
             int32_t refreshType, const CasData &refreshData) override;
diff --git a/drm/mediadrm/plugins/clearkey/hidl/Android.bp b/drm/mediadrm/plugins/clearkey/hidl/Android.bp
index b44a6c7..e91e918 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/Android.bp
+++ b/drm/mediadrm/plugins/clearkey/hidl/Android.bp
@@ -14,8 +14,8 @@
 // limitations under the License.
 //
 
-cc_binary {
-    name: "android.hardware.drm@1.2-service.clearkey",
+cc_defaults {
+    name: "clearkey_service_defaults",
     vendor: true,
 
     srcs: [
@@ -33,13 +33,11 @@
         "MemoryFileSystem.cpp",
         "Session.cpp",
         "SessionLibrary.cpp",
-        "service.cpp",
     ],
 
     relative_install_path: "hw",
 
     cflags: ["-Wall", "-Werror"],
-    init_rc: ["android.hardware.drm@1.2-service.clearkey.rc"],
 
     shared_libs: [
         "android.hardware.drm@1.0",
@@ -80,3 +78,16 @@
     },
     srcs: ["protos/DeviceFiles.proto"],
 }
+cc_binary {
+    name: "android.hardware.drm@1.2-service.clearkey",
+    defaults: ["clearkey_service_defaults"],
+    srcs: ["service.cpp"],
+    init_rc: ["android.hardware.drm@1.2-service.clearkey.rc"],
+}
+cc_binary {
+    name: "android.hardware.drm@1.2-service-lazy.clearkey",
+    overrides: ["android.hardware.drm@1.2-service.clearkey"],
+    defaults: ["clearkey_service_defaults"],
+    srcs: ["serviceLazy.cpp"],
+    init_rc: ["android.hardware.drm@1.2-service-lazy.clearkey.rc"],
+}
diff --git a/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service-lazy.clearkey.rc b/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service-lazy.clearkey.rc
new file mode 100644
index 0000000..9afd3d7
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service-lazy.clearkey.rc
@@ -0,0 +1,14 @@
+service vendor.drm-clearkey-hal-1-2 /vendor/bin/hw/android.hardware.drm@1.2-service-lazy.clearkey
+    interface android.hardware.drm@1.0::ICryptoFactory clearkey
+    interface android.hardware.drm@1.0::IDrmFactory clearkey
+    interface android.hardware.drm@1.1::ICryptoFactory clearkey
+    interface android.hardware.drm@1.1::IDrmFactory clearkey
+    interface android.hardware.drm@1.2::ICryptoFactory clearkey
+    interface android.hardware.drm@1.2::IDrmFactory clearkey
+    disabled
+    oneshot
+    class hal
+    user media
+    group media mediadrm
+    ioprio rt 4
+    writepid /dev/cpuset/foreground/tasks
diff --git a/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service.clearkey.rc b/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service.clearkey.rc
index ac184f7..5ba669d 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service.clearkey.rc
+++ b/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service.clearkey.rc
@@ -1,4 +1,10 @@
 service vendor.drm-clearkey-hal-1-2 /vendor/bin/hw/android.hardware.drm@1.2-service.clearkey
+    interface android.hardware.drm@1.0::ICryptoFactory clearkey
+    interface android.hardware.drm@1.0::IDrmFactory clearkey
+    interface android.hardware.drm@1.1::ICryptoFactory clearkey
+    interface android.hardware.drm@1.1::IDrmFactory clearkey
+    interface android.hardware.drm@1.2::ICryptoFactory clearkey
+    interface android.hardware.drm@1.2::IDrmFactory clearkey
     class hal
     user media
     group media mediadrm
diff --git a/drm/mediadrm/plugins/clearkey/hidl/service.cpp b/drm/mediadrm/plugins/clearkey/hidl/service.cpp
index 4ca31f3..b39ea01 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/service.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/service.cpp
@@ -13,13 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define LOG_TAG "android.hardware.drm@1.2-service.clearkey"
-
 #include <CryptoFactory.h>
 #include <DrmFactory.h>
 
 #include <android-base/logging.h>
 #include <binder/ProcessState.h>
+#include <hidl/HidlLazyUtils.h>
 #include <hidl/HidlTransportSupport.h>
 
 using ::android::hardware::configureRpcThreadpool;
@@ -31,14 +30,7 @@
 using android::hardware::drm::V1_2::clearkey::CryptoFactory;
 using android::hardware::drm::V1_2::clearkey::DrmFactory;
 
-
 int main(int /* argc */, char** /* argv */) {
-    ALOGD("android.hardware.drm@1.2-service.clearkey starting...");
-
-    // The DRM HAL may communicate to other vendor components via
-    // /dev/vndbinder
-    android::ProcessState::initWithDriver("/dev/vndbinder");
-
     sp<IDrmFactory> drmFactory = new DrmFactory;
     sp<ICryptoFactory> cryptoFactory = new CryptoFactory;
 
diff --git a/drm/mediadrm/plugins/clearkey/hidl/serviceLazy.cpp b/drm/mediadrm/plugins/clearkey/hidl/serviceLazy.cpp
new file mode 100644
index 0000000..99fd883
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/serviceLazy.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2019 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.
+ */
+#include <CryptoFactory.h>
+#include <DrmFactory.h>
+
+#include <android-base/logging.h>
+#include <binder/ProcessState.h>
+#include <hidl/HidlLazyUtils.h>
+#include <hidl/HidlTransportSupport.h>
+
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::joinRpcThreadpool;
+using ::android::sp;
+
+using android::hardware::drm::V1_2::ICryptoFactory;
+using android::hardware::drm::V1_2::IDrmFactory;
+using android::hardware::drm::V1_2::clearkey::CryptoFactory;
+using android::hardware::drm::V1_2::clearkey::DrmFactory;
+using android::hardware::LazyServiceRegistrar;
+
+int main(int /* argc */, char** /* argv */) {
+    sp<IDrmFactory> drmFactory = new DrmFactory;
+    sp<ICryptoFactory> cryptoFactory = new CryptoFactory;
+
+    configureRpcThreadpool(8, true /* callerWillJoin */);
+
+    // Setup hwbinder service
+    LazyServiceRegistrar serviceRegistrar;
+
+    // Setup hwbinder service
+    CHECK_EQ(serviceRegistrar.registerService(drmFactory, "clearkey"), android::NO_ERROR)
+        << "Failed to register Clearkey Factory HAL";
+    CHECK_EQ(serviceRegistrar.registerService(cryptoFactory, "clearkey"), android::NO_ERROR)
+        << "Failed to register Clearkey Crypto  HAL";
+
+    joinRpcThreadpool();
+}
diff --git a/media/audioserver/Android.mk b/media/audioserver/Android.mk
index f05c84b..10d8b13 100644
--- a/media/audioserver/Android.mk
+++ b/media/audioserver/Android.mk
@@ -19,7 +19,8 @@
 	libnbaio \
 	libnblog \
 	libsoundtriggerservice \
-	libutils
+	libutils \
+	libvibrator
 
 # TODO oboeservice is the old folder name for aaudioservice. It will be changed.
 LOCAL_C_INCLUDES := \
diff --git a/media/codec2/components/avc/C2SoftAvcEnc.cpp b/media/codec2/components/avc/C2SoftAvcEnc.cpp
index cf06623..6ddb9ff 100644
--- a/media/codec2/components/avc/C2SoftAvcEnc.cpp
+++ b/media/codec2/components/avc/C2SoftAvcEnc.cpp
@@ -216,7 +216,7 @@
         };
 
         uint64_t mbs = uint64_t((size.v.width + 15) / 16) * ((size.v.height + 15) / 16);
-        float mbsPerSec = float(mbs) / frameRate.v.value;
+        float mbsPerSec = float(mbs) * frameRate.v.value;
 
         // Check if the supplied level meets the MB / bitrate requirements. If
         // not, update the level with the lowest level meeting the requirements.
diff --git a/media/codec2/core/include/C2Config.h b/media/codec2/core/include/C2Config.h
index 23939b5..0357115 100644
--- a/media/codec2/core/include/C2Config.h
+++ b/media/codec2/core/include/C2Config.h
@@ -180,6 +180,7 @@
 
     kParamIndexPictureTypeMask,
     kParamIndexPictureType,
+    kParamIndexHdr10PlusMetadata,
 
     /* ------------------------------------ video components ------------------------------------ */
 
@@ -194,7 +195,6 @@
     kParamIndexLayerIndex,
     kParamIndexLayerCount,
     kParamIndexIntraRefresh,
-    kParamIndexHdr10PlusMetadata,
 
     /* ------------------------------------ image components ------------------------------------ */
 
diff --git a/media/codec2/hidl/1.0/utils/Android.bp b/media/codec2/hidl/1.0/utils/Android.bp
index c5ad6a0..d0296a5 100644
--- a/media/codec2/hidl/1.0/utils/Android.bp
+++ b/media/codec2/hidl/1.0/utils/Android.bp
@@ -8,8 +8,10 @@
 
     srcs: [
         "Component.cpp",
+        "ComponentInterface.cpp",
         "ComponentStore.cpp",
         "Configurable.cpp",
+        "InputBufferManager.cpp",
         "InputSurface.cpp",
         "InputSurfaceConnection.cpp",
         "types.cpp",
diff --git a/media/codec2/hidl/1.0/utils/Component.cpp b/media/codec2/hidl/1.0/utils/Component.cpp
index 5ae1972..0473b57 100644
--- a/media/codec2/hidl/1.0/utils/Component.cpp
+++ b/media/codec2/hidl/1.0/utils/Component.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -18,11 +18,11 @@
 #define LOG_TAG "Codec2-Component"
 #include <android-base/logging.h>
 
-#include <C2PlatformSupport.h>
 #include <codec2/hidl/1.0/Component.h>
 #include <codec2/hidl/1.0/ComponentStore.h>
-#include <codec2/hidl/1.0/types.h>
+#include <codec2/hidl/1.0/InputBufferManager.h>
 
+#include <android/hardware/media/c2/1.0/IInputSink.h>
 #include <hidl/HidlBinderSupport.h>
 #include <utils/Timers.h>
 
@@ -42,281 +42,6 @@
 
 using namespace ::android;
 
-namespace /* unnamed */ {
-
-// Implementation of ConfigurableC2Intf based on C2ComponentInterface
-struct CompIntf : public ConfigurableC2Intf {
-    CompIntf(const std::shared_ptr<C2ComponentInterface>& intf) :
-        ConfigurableC2Intf(intf->getName()),
-        mIntf(intf) {
-    }
-
-    virtual c2_status_t config(
-            const std::vector<C2Param*>& params,
-            c2_blocking_t mayBlock,
-            std::vector<std::unique_ptr<C2SettingResult>>* const failures
-            ) override {
-        ALOGV("config");
-        return mIntf->config_vb(params, mayBlock, failures);
-    }
-
-    virtual c2_status_t query(
-            const std::vector<C2Param::Index>& indices,
-            c2_blocking_t mayBlock,
-            std::vector<std::unique_ptr<C2Param>>* const params
-            ) const override {
-        ALOGV("query");
-        return mIntf->query_vb({}, indices, mayBlock, params);
-    }
-
-    virtual c2_status_t querySupportedParams(
-            std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
-            ) const override {
-        ALOGV("querySupportedParams");
-        return mIntf->querySupportedParams_nb(params);
-    }
-
-    virtual c2_status_t querySupportedValues(
-            std::vector<C2FieldSupportedValuesQuery>& fields,
-            c2_blocking_t mayBlock) const override {
-        ALOGV("querySupportedValues");
-        return mIntf->querySupportedValues_vb(fields, mayBlock);
-    }
-
-protected:
-    std::shared_ptr<C2ComponentInterface> mIntf;
-};
-
-} // unnamed namespace
-
-// InputBufferManager
-// ==================
-//
-// InputBufferManager presents a way to track and untrack input buffers in this
-// (codec) process and send a notification to a listener, possibly in a
-// different process, when a tracked buffer no longer has any references in this
-// process. (In fact, this class would work for listeners in the same process
-// too, but the optimization discussed below will not be beneficial.)
-//
-// InputBufferManager holds a collection of records representing tracked buffers
-// and their callback listeners. Conceptually, one record is a triple (listener,
-// frameIndex, bufferIndex) where
-//
-// - (frameIndex, bufferIndex) is a pair of indices used to identify the buffer.
-// - listener is of type IComponentListener. Its onFramesRendered() function
-//   will be called after the associated buffer dies. The argument of
-//   onFramesRendered() is a list of RenderedFrame objects, each of which has
-//   the following members:
-//
-//     uint64_t bufferQueueId
-//     int32_t  slotId
-//     int64_t  timestampNs
-//
-// When a tracked buffer associated to the triple (listener, frameIndex,
-// bufferIndex) goes out of scope, listener->onFramesRendered() will be called
-// with a RenderedFrame object whose members are set as follows:
-//
-//     bufferQueueId = frameIndex
-//     slotId        = ~bufferIndex
-//     timestampNs   = systemTime() at the time of notification
-//
-// The reason for the bitwise negation of bufferIndex is that onFramesRendered()
-// may be used for a different purpose when slotId is non-negative (which is a
-// more general use case).
-//
-// IPC Optimization
-// ----------------
-//
-// Since onFramesRendered() generally is an IPC call, InputBufferManager tries
-// not to call it too often. There is a mechanism to guarantee that any two
-// calls to the same listener are at least kNotificationPeriodNs nanoseconds
-// apart.
-//
-struct InputBufferManager {
-    // The minimum time period between IPC calls to notify the client about the
-    // destruction of input buffers.
-    static constexpr nsecs_t kNotificationPeriodNs = 1000000;
-
-    // Track all buffers in a C2FrameData object.
-    //
-    // input (C2FrameData) has the following two members that are of interest:
-    //
-    //   C2WorkOrdinal                ordinal
-    //   vector<shared_ptr<C2Buffer>> buffers
-    //
-    // Calling registerFrameData(listener, input) will register multiple
-    // triples (, frameIndex, bufferIndex) where frameIndex is equal to
-    // input.ordinal.frameIndex and bufferIndex runs through the indices of
-    // input.buffers such that input.buffers[bufferIndex] is not null.
-    //
-    // This should be called from queue().
-    static void registerFrameData(
-            const sp<IComponentListener>& listener,
-            const C2FrameData& input);
-
-    // Untrack all buffers in a C2FrameData object.
-    //
-    // Calling unregisterFrameData(listener, input) will unregister and remove
-    // pending notifications for all triples (l, fi, bufferIndex) such that
-    // l = listener and fi = input.ordinal.frameIndex.
-    //
-    // This should be called from onWorkDone() and flush().
-    static void unregisterFrameData(
-            const wp<IComponentListener>& listener,
-            const C2FrameData& input);
-
-    // Untrack all buffers associated to a given listener.
-    //
-    // Calling unregisterFrameData(listener) will unregister and remove
-    // pending notifications for all triples (l, frameIndex, bufferIndex) such
-    // that l = listener.
-    //
-    // This should be called when the component cleans up all input buffers,
-    // i.e., when reset(), release(), stop() or ~Component() is called.
-    static void unregisterFrameData(
-            const wp<IComponentListener>& listener);
-
-private:
-    void _registerFrameData(
-            const sp<IComponentListener>& listener,
-            const C2FrameData& input);
-    void _unregisterFrameData(
-            const wp<IComponentListener>& listener,
-            const C2FrameData& input);
-    void _unregisterFrameData(
-            const wp<IComponentListener>& listener);
-
-    // The callback function tied to C2Buffer objects.
-    //
-    // Note: This function assumes that sInstance is the only instance of this
-    //       class.
-    static void onBufferDestroyed(const C2Buffer* buf, void* arg);
-    void _onBufferDestroyed(const C2Buffer* buf, void* arg);
-
-    // Comparison operator for weak pointers.
-    struct CompareWeakComponentListener {
-        constexpr bool operator()(
-                const wp<IComponentListener>& x,
-                const wp<IComponentListener>& y) const {
-            return x.get_refs() < y.get_refs();
-        }
-    };
-
-    // Persistent data to be passed as "arg" in onBufferDestroyed().
-    // This is essentially the triple (listener, frameIndex, bufferIndex) plus a
-    // weak pointer to the C2Buffer object.
-    //
-    // Note that the "key" is bufferIndex according to operator<(). This is
-    // designed to work with TrackedBuffersMap defined below.
-    struct TrackedBuffer {
-        wp<IComponentListener> listener;
-        uint64_t frameIndex;
-        size_t bufferIndex;
-        std::weak_ptr<C2Buffer> buffer;
-        TrackedBuffer(const wp<IComponentListener>& listener,
-                      uint64_t frameIndex,
-                      size_t bufferIndex,
-                      const std::shared_ptr<C2Buffer>& buffer)
-              : listener(listener),
-                frameIndex(frameIndex),
-                bufferIndex(bufferIndex),
-                buffer(buffer) {}
-        TrackedBuffer(const TrackedBuffer&) = default;
-        bool operator<(const TrackedBuffer& other) const {
-            return bufferIndex < other.bufferIndex;
-        }
-    };
-
-    // Map: listener -> frameIndex -> set<TrackedBuffer>.
-    // Essentially, this is used to store triples (listener, frameIndex,
-    // bufferIndex) that's searchable by listener and (listener, frameIndex).
-    // However, the value of the innermost map is TrackedBuffer, which also
-    // contains an extra copy of listener and frameIndex. This is needed
-    // because onBufferDestroyed() needs to know listener and frameIndex too.
-    typedef std::map<wp<IComponentListener>,
-                     std::map<uint64_t,
-                              std::set<TrackedBuffer>>,
-                     CompareWeakComponentListener> TrackedBuffersMap;
-
-    // Storage for pending (unsent) death notifications for one listener.
-    // Each pair in member named "indices" are (frameIndex, bufferIndex) from
-    // the (listener, frameIndex, bufferIndex) triple.
-    struct DeathNotifications {
-
-        // The number of pending notifications for this listener.
-        // count may be 0, in which case the DeathNotifications object will
-        // remain valid for only a small period (kNotificationPeriodNs
-        // nanoseconds).
-        size_t count;
-
-        // The timestamp of the most recent callback on this listener. This is
-        // used to guarantee that callbacks do not occur too frequently, and
-        // also to trigger expiration of a DeathNotifications object that has
-        // count = 0.
-        nsecs_t lastSentNs;
-
-        // Map: frameIndex -> vector of bufferIndices
-        // This is essentially a collection of (framdeIndex, bufferIndex).
-        std::map<uint64_t, std::vector<size_t>> indices;
-
-        DeathNotifications()
-              : count(0),
-                lastSentNs(systemTime() - kNotificationPeriodNs),
-                indices() {}
-    };
-
-    // Mutex for the management of all input buffers.
-    std::mutex mMutex;
-
-    // Tracked input buffers.
-    TrackedBuffersMap mTrackedBuffersMap;
-
-    // Death notifications to be sent.
-    //
-    // A DeathNotifications object is associated to each listener. An entry in
-    // this map will be removed if its associated DeathNotifications has count =
-    // 0 and lastSentNs < systemTime() - kNotificationPeriodNs.
-    std::map<wp<IComponentListener>, DeathNotifications> mDeathNotifications;
-
-    // Condition variable signaled when an entry is added to mDeathNotifications.
-    std::condition_variable mOnBufferDestroyed;
-
-    // Notify the clients about buffer destructions.
-    // Return false if all destructions have been notified.
-    // Return true and set timeToRetry to the duration to wait for before
-    // retrying if some destructions have not been notified.
-    bool processNotifications(nsecs_t* timeToRetryNs);
-
-    // Main function for the input buffer manager thread.
-    void main();
-
-    // The thread that manages notifications.
-    //
-    // Note: This variable is declared last so its initialization will happen
-    // after all other member variables have been initialized.
-    std::thread mMainThread;
-
-    // Private constructor.
-    InputBufferManager();
-
-    // The only instance of this class.
-    static InputBufferManager& getInstance();
-
-};
-
-// ComponentInterface
-ComponentInterface::ComponentInterface(
-        const std::shared_ptr<C2ComponentInterface>& intf,
-        const sp<ComponentStore>& store) :
-    Configurable(new CachedConfigurable(std::make_unique<CompIntf>(intf))),
-    mInterface(intf) {
-    mInit = init(store.get());
-}
-
-c2_status_t ComponentInterface::status() const {
-    return mInit;
-}
-
 // ComponentListener wrapper
 struct Component::Listener : public C2Component::Listener {
 
@@ -328,12 +53,12 @@
     virtual void onError_nb(
             std::weak_ptr<C2Component> /* c2component */,
             uint32_t errorCode) override {
-        ALOGV("onError");
         sp<IComponentListener> listener = mListener.promote();
         if (listener) {
             Return<void> transStatus = listener->onError(Status::OK, errorCode);
             if (!transStatus.isOk()) {
-                ALOGE("onError -- transaction failed.");
+                LOG(ERROR) << "Component::Listener::onError_nb -- "
+                           << "transaction failed.";
             }
         }
     }
@@ -342,7 +67,6 @@
             std::weak_ptr<C2Component> /* c2component */,
             std::vector<std::shared_ptr<C2SettingResult>> c2settingResult
             ) override {
-        ALOGV("onTripped");
         sp<IComponentListener> listener = mListener.promote();
         if (listener) {
             hidl_vec<SettingResult> settingResults(c2settingResult.size());
@@ -350,8 +74,7 @@
             for (const std::shared_ptr<C2SettingResult> &c2result :
                     c2settingResult) {
                 if (c2result) {
-                    if (objcpy(&settingResults[ix++], *c2result) !=
-                            Status::OK) {
+                    if (!objcpy(&settingResults[ix++], *c2result)) {
                         break;
                     }
                 }
@@ -359,7 +82,8 @@
             settingResults.resize(ix);
             Return<void> transStatus = listener->onTripped(settingResults);
             if (!transStatus.isOk()) {
-                ALOGE("onTripped -- transaction failed.");
+                LOG(ERROR) << "Component::Listener::onTripped_nb -- "
+                           << "transaction failed.";
             }
         }
     }
@@ -367,7 +91,6 @@
     virtual void onWorkDone_nb(
             std::weak_ptr<C2Component> /* c2component */,
             std::list<std::unique_ptr<C2Work>> c2workItems) override {
-        ALOGV("onWorkDone");
         for (const std::unique_ptr<C2Work>& work : c2workItems) {
             if (work) {
                 if (work->worklets.empty()
@@ -385,15 +108,16 @@
             WorkBundle workBundle;
 
             sp<Component> strongComponent = mComponent.promote();
-            if (objcpy(&workBundle, c2workItems, strongComponent ?
-                    &strongComponent->mBufferPoolSender : nullptr)
-                    != Status::OK) {
-                ALOGE("onWorkDone() received corrupted work items.");
+            if (!objcpy(&workBundle, c2workItems, strongComponent ?
+                    &strongComponent->mBufferPoolSender : nullptr)) {
+                LOG(ERROR) << "Component::Listener::onWorkDone_nb -- "
+                           << "received corrupted work items.";
                 return;
             }
             Return<void> transStatus = listener->onWorkDone(workBundle);
             if (!transStatus.isOk()) {
-                ALOGE("onWorkDone -- transaction failed.");
+                LOG(ERROR) << "Component::Listener::onWorkDone_nb -- "
+                           << "transaction failed.";
                 return;
             }
             yieldBufferQueueBlocks(c2workItems, true);
@@ -405,23 +129,86 @@
     wp<IComponentListener> mListener;
 };
 
+// Component::Sink
+struct Component::Sink : public IInputSink {
+    std::shared_ptr<Component> mComponent;
+    sp<IConfigurable> mConfigurable;
+
+    virtual Return<Status> queue(const WorkBundle& workBundle) override {
+        return mComponent->queue(workBundle);
+    }
+
+    virtual Return<sp<IConfigurable>> getConfigurable() override {
+        return mConfigurable;
+    }
+
+    Sink(const std::shared_ptr<Component>& component);
+    virtual ~Sink() override;
+
+    // Process-wide map: Component::Sink -> C2Component.
+    static std::mutex sSink2ComponentMutex;
+    static std::map<IInputSink*, std::weak_ptr<C2Component>> sSink2Component;
+
+    static std::shared_ptr<C2Component> findLocalComponent(
+            const sp<IInputSink>& sink);
+};
+
+std::mutex
+        Component::Sink::sSink2ComponentMutex{};
+std::map<IInputSink*, std::weak_ptr<C2Component>>
+        Component::Sink::sSink2Component{};
+
+Component::Sink::Sink(const std::shared_ptr<Component>& component)
+        : mComponent{component},
+          mConfigurable{[&component]() -> sp<IConfigurable> {
+              Return<sp<IComponentInterface>> ret1 = component->getInterface();
+              if (!ret1.isOk()) {
+                  LOG(ERROR) << "Sink::Sink -- component's transaction failed.";
+                  return nullptr;
+              }
+              Return<sp<IConfigurable>> ret2 =
+                      static_cast<sp<IComponentInterface>>(ret1)->
+                      getConfigurable();
+              if (!ret2.isOk()) {
+                  LOG(ERROR) << "Sink::Sink -- interface's transaction failed.";
+                  return nullptr;
+              }
+              return static_cast<sp<IConfigurable>>(ret2);
+          }()} {
+    std::lock_guard<std::mutex> lock(sSink2ComponentMutex);
+    sSink2Component.emplace(this, component->mComponent);
+}
+
+Component::Sink::~Sink() {
+    std::lock_guard<std::mutex> lock(sSink2ComponentMutex);
+    sSink2Component.erase(this);
+}
+
+std::shared_ptr<C2Component> Component::Sink::findLocalComponent(
+        const sp<IInputSink>& sink) {
+    std::lock_guard<std::mutex> lock(sSink2ComponentMutex);
+    auto i = sSink2Component.find(sink.get());
+    if (i == sSink2Component.end()) {
+        return nullptr;
+    }
+    return i->second.lock();
+}
+
 // Component
 Component::Component(
         const std::shared_ptr<C2Component>& component,
         const sp<IComponentListener>& listener,
         const sp<ComponentStore>& store,
         const sp<::android::hardware::media::bufferpool::V2_0::
-        IClientManager>& clientPoolManager) :
-    Configurable(new CachedConfigurable(
-            std::make_unique<CompIntf>(component->intf()))),
-    mComponent(component),
-    mInterface(component->intf()),
-    mListener(listener),
-    mStore(store),
-    mBufferPoolSender(clientPoolManager) {
+        IClientManager>& clientPoolManager)
+      : mComponent{component},
+        mInterface{new ComponentInterface(component->intf(), store.get())},
+        mListener{listener},
+        mStore{store},
+        mBufferPoolSender{clientPoolManager} {
     // Retrieve supported parameters from store
     // TODO: We could cache this per component/interface type
-    mInit = init(store.get());
+    mInit = mInterface->status();
 }
 
 c2_status_t Component::status() const {
@@ -430,11 +217,9 @@
 
 // Methods from ::android::hardware::media::c2::V1_0::IComponent
 Return<Status> Component::queue(const WorkBundle& workBundle) {
-    ALOGV("queue -- converting input");
     std::list<std::unique_ptr<C2Work>> c2works;
 
-    if (objcpy(&c2works, workBundle) != C2_OK) {
-        ALOGV("queue -- corrupted");
+    if (!objcpy(&c2works, workBundle)) {
         return Status::CORRUPTED;
     }
 
@@ -446,13 +231,11 @@
         }
     }
 
-    ALOGV("queue -- calling");
     return static_cast<Status>(mComponent->queue_nb(&c2works));
 }
 
 Return<void> Component::flush(flush_cb _hidl_cb) {
     std::list<std::unique_ptr<C2Work>> c2flushedWorks;
-    ALOGV("flush -- calling");
     c2_status_t c2res = mComponent->flush_sm(
             C2Component::FLUSH_COMPONENT,
             &c2flushedWorks);
@@ -473,8 +256,9 @@
     WorkBundle flushedWorkBundle;
     Status res = static_cast<Status>(c2res);
     if (c2res == C2_OK) {
-        ALOGV("flush -- converting output");
-        res = objcpy(&flushedWorkBundle, c2flushedWorks, &mBufferPoolSender);
+        if (!objcpy(&flushedWorkBundle, c2flushedWorks, &mBufferPoolSender)) {
+            res = Status::CORRUPTED;
+        }
     }
     _hidl_cb(res, flushedWorkBundle);
     yieldBufferQueueBlocks(c2flushedWorks, true);
@@ -482,7 +266,6 @@
 }
 
 Return<Status> Component::drain(bool withEos) {
-    ALOGV("drain");
     return static_cast<Status>(mComponent->drain_nb(withEos ?
             C2Component::DRAIN_COMPONENT_WITH_EOS :
             C2Component::DRAIN_COMPONENT_NO_EOS));
@@ -512,14 +295,39 @@
     return Status::OK;
 }
 
-Return<Status> Component::connectToOmxInputSurface(
+Return<void> Component::connectToInputSurface(
+        const sp<IInputSurface>& inputSurface,
+        connectToInputSurface_cb _hidl_cb) {
+    sp<Sink> sink;
+    {
+        std::lock_guard<std::mutex> lock(mSinkMutex);
+        if (!mSink) {
+            mSink = new Sink(shared_from_this());
+        }
+        sink = mSink;
+    }
+    Status status;
+    sp<IInputSurfaceConnection> connection;
+    auto transStatus = inputSurface->connect(sink,
+            [&status, &connection](Status s,
+                                   const sp<IInputSurfaceConnection>& c) {
+                status = s;
+                connection = c;
+            }
+        );
+    _hidl_cb(status, connection);
+    return Void();
+}
+
+Return<void> Component::connectToOmxInputSurface(
         const sp<HGraphicBufferProducer>& producer,
         const sp<::android::hardware::media::omx::V1_0::
-        IGraphicBufferSource>& source) {
-    // TODO implement
+        IGraphicBufferSource>& source,
+        connectToOmxInputSurface_cb _hidl_cb) {
     (void)producer;
     (void)source;
-    return Status::OMITTED;
+    (void)_hidl_cb;
+    return Void();
 }
 
 Return<Status> Component::disconnectFromInputSurface() {
@@ -530,11 +338,12 @@
 namespace /* unnamed */ {
 
 struct BlockPoolIntf : public ConfigurableC2Intf {
-    BlockPoolIntf(const std::shared_ptr<C2BlockPool>& pool) :
-        ConfigurableC2Intf("C2BlockPool:" +
-                           (pool ? std::to_string(pool->getLocalId()) :
-                           "null")),
-        mPool(pool) {
+    BlockPoolIntf(const std::shared_ptr<C2BlockPool>& pool)
+          : ConfigurableC2Intf{
+                "C2BlockPool:" +
+                    (pool ? std::to_string(pool->getLocalId()) : "null"),
+                0},
+            mPool{pool} {
     }
 
     virtual c2_status_t config(
@@ -613,18 +422,15 @@
 }
 
 Return<Status> Component::start() {
-    ALOGV("start");
     return static_cast<Status>(mComponent->start());
 }
 
 Return<Status> Component::stop() {
-    ALOGV("stop");
     InputBufferManager::unregisterFrameData(mListener);
     return static_cast<Status>(mComponent->stop());
 }
 
 Return<Status> Component::reset() {
-    ALOGV("reset");
     Status status = static_cast<Status>(mComponent->reset());
     {
         std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
@@ -635,7 +441,6 @@
 }
 
 Return<Status> Component::release() {
-    ALOGV("release");
     Status status = static_cast<Status>(mComponent->release());
     {
         std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
@@ -645,8 +450,13 @@
     return status;
 }
 
-void Component::setLocalId(const Component::LocalId& localId) {
-    mLocalId = localId;
+Return<sp<IComponentInterface>> Component::getInterface() {
+    return sp<IComponentInterface>(mInterface);
+}
+
+std::shared_ptr<C2Component> Component::findLocalComponent(
+        const sp<IInputSink>& sink) {
+    return Component::Sink::findLocalComponent(sink);
 }
 
 void Component::initListener(const sp<Component>& self) {
@@ -660,395 +470,7 @@
 
 Component::~Component() {
     InputBufferManager::unregisterFrameData(mListener);
-    mStore->reportComponentDeath(mLocalId);
-}
-
-Component::InterfaceKey::InterfaceKey(const sp<IComponent>& component) {
-    isRemote = component->isRemote();
-    if (isRemote) {
-        remote = ::android::hardware::toBinder(component);
-    } else {
-        local = component;
-    }
-}
-
-// InputBufferManager implementation
-
-constexpr nsecs_t InputBufferManager::kNotificationPeriodNs;
-
-void InputBufferManager::registerFrameData(
-        const sp<IComponentListener>& listener,
-        const C2FrameData& input) {
-    getInstance()._registerFrameData(listener, input);
-}
-
-void InputBufferManager::unregisterFrameData(
-        const wp<IComponentListener>& listener,
-        const C2FrameData& input) {
-    getInstance()._unregisterFrameData(listener, input);
-}
-
-void InputBufferManager::unregisterFrameData(
-        const wp<IComponentListener>& listener) {
-    getInstance()._unregisterFrameData(listener);
-}
-
-void InputBufferManager::_registerFrameData(
-        const sp<IComponentListener>& listener,
-        const C2FrameData& input) {
-    uint64_t frameIndex = input.ordinal.frameIndex.peeku();
-    ALOGV("InputBufferManager::_registerFrameData called "
-          "(listener @ %p, frameIndex = %llu)",
-          listener.get(),
-          static_cast<long long unsigned>(frameIndex));
-    std::lock_guard<std::mutex> lock(mMutex);
-
-    std::set<TrackedBuffer> &bufferIds =
-            mTrackedBuffersMap[listener][frameIndex];
-
-    for (size_t i = 0; i < input.buffers.size(); ++i) {
-        if (!input.buffers[i]) {
-            ALOGV("InputBufferManager::_registerFrameData: "
-                  "Input buffer at index %zu is null", i);
-            continue;
-        }
-        const TrackedBuffer &bufferId =
-                *bufferIds.emplace(listener, frameIndex, i, input.buffers[i]).
-                first;
-
-        c2_status_t status = input.buffers[i]->registerOnDestroyNotify(
-                onBufferDestroyed,
-                const_cast<void*>(reinterpret_cast<const void*>(&bufferId)));
-        if (status != C2_OK) {
-            ALOGD("InputBufferManager: registerOnDestroyNotify failed "
-                  "(listener @ %p, frameIndex = %llu, bufferIndex = %zu) "
-                  "=> %s (%d)",
-                  listener.get(),
-                  static_cast<unsigned long long>(frameIndex),
-                  i,
-                  asString(status), static_cast<int>(status));
-        }
-    }
-
-    mDeathNotifications.emplace(listener, DeathNotifications());
-}
-
-// Remove a pair (listener, frameIndex) from mTrackedBuffersMap and
-// mDeathNotifications. This implies all bufferIndices are removed.
-//
-// This is called from onWorkDone() and flush().
-void InputBufferManager::_unregisterFrameData(
-        const wp<IComponentListener>& listener,
-        const C2FrameData& input) {
-    uint64_t frameIndex = input.ordinal.frameIndex.peeku();
-    ALOGV("InputBufferManager::_unregisterFrameData called "
-          "(listener @ %p, frameIndex = %llu)",
-          listener.unsafe_get(),
-          static_cast<long long unsigned>(frameIndex));
-    std::lock_guard<std::mutex> lock(mMutex);
-
-    auto findListener = mTrackedBuffersMap.find(listener);
-    if (findListener != mTrackedBuffersMap.end()) {
-        std::map<uint64_t, std::set<TrackedBuffer>> &frameIndex2BufferIds
-                = findListener->second;
-        auto findFrameIndex = frameIndex2BufferIds.find(frameIndex);
-        if (findFrameIndex != frameIndex2BufferIds.end()) {
-            std::set<TrackedBuffer> &bufferIds = findFrameIndex->second;
-            for (const TrackedBuffer& bufferId : bufferIds) {
-                std::shared_ptr<C2Buffer> buffer = bufferId.buffer.lock();
-                if (buffer) {
-                    c2_status_t status = buffer->unregisterOnDestroyNotify(
-                            onBufferDestroyed,
-                            const_cast<void*>(
-                            reinterpret_cast<const void*>(&bufferId)));
-                    if (status != C2_OK) {
-                        ALOGD("InputBufferManager: "
-                              "unregisterOnDestroyNotify failed "
-                              "(listener @ %p, "
-                              "frameIndex = %llu, "
-                              "bufferIndex = %zu) "
-                              "=> %s (%d)",
-                              bufferId.listener.unsafe_get(),
-                              static_cast<unsigned long long>(
-                                  bufferId.frameIndex),
-                              bufferId.bufferIndex,
-                              asString(status), static_cast<int>(status));
-                    }
-                }
-            }
-
-            frameIndex2BufferIds.erase(findFrameIndex);
-            if (frameIndex2BufferIds.empty()) {
-                mTrackedBuffersMap.erase(findListener);
-            }
-        }
-    }
-
-    auto findListenerD = mDeathNotifications.find(listener);
-    if (findListenerD != mDeathNotifications.end()) {
-        DeathNotifications &deathNotifications = findListenerD->second;
-        auto findFrameIndex = deathNotifications.indices.find(frameIndex);
-        if (findFrameIndex != deathNotifications.indices.end()) {
-            std::vector<size_t> &bufferIndices = findFrameIndex->second;
-            deathNotifications.count -= bufferIndices.size();
-            deathNotifications.indices.erase(findFrameIndex);
-        }
-    }
-}
-
-// Remove listener from mTrackedBuffersMap and mDeathNotifications. This implies
-// all frameIndices and bufferIndices are removed.
-//
-// This is called when the component cleans up all input buffers, i.e., when
-// reset(), release(), stop() or ~Component() is called.
-void InputBufferManager::_unregisterFrameData(
-        const wp<IComponentListener>& listener) {
-    ALOGV("InputBufferManager::_unregisterFrameData called (listener @ %p)",
-            listener.unsafe_get());
-    std::lock_guard<std::mutex> lock(mMutex);
-
-    auto findListener = mTrackedBuffersMap.find(listener);
-    if (findListener != mTrackedBuffersMap.end()) {
-        std::map<uint64_t, std::set<TrackedBuffer>> &frameIndex2BufferIds =
-                findListener->second;
-        for (auto findFrameIndex = frameIndex2BufferIds.begin();
-                findFrameIndex != frameIndex2BufferIds.end();
-                ++findFrameIndex) {
-            std::set<TrackedBuffer> &bufferIds = findFrameIndex->second;
-            for (const TrackedBuffer& bufferId : bufferIds) {
-                std::shared_ptr<C2Buffer> buffer = bufferId.buffer.lock();
-                if (buffer) {
-                    c2_status_t status = buffer->unregisterOnDestroyNotify(
-                            onBufferDestroyed,
-                            const_cast<void*>(
-                            reinterpret_cast<const void*>(&bufferId)));
-                    if (status != C2_OK) {
-                        ALOGD("InputBufferManager: "
-                              "unregisterOnDestroyNotify failed "
-                              "(listener @ %p, "
-                              "frameIndex = %llu, "
-                              "bufferIndex = %zu) "
-                              "=> %s (%d)",
-                              bufferId.listener.unsafe_get(),
-                              static_cast<unsigned long long>(bufferId.frameIndex),
-                              bufferId.bufferIndex,
-                              asString(status), static_cast<int>(status));
-                    }
-                }
-            }
-        }
-        mTrackedBuffersMap.erase(findListener);
-    }
-
-    mDeathNotifications.erase(listener);
-}
-
-// Move a buffer from mTrackedBuffersMap to mDeathNotifications.
-// This is called when a registered C2Buffer object is destroyed.
-void InputBufferManager::onBufferDestroyed(const C2Buffer* buf, void* arg) {
-    getInstance()._onBufferDestroyed(buf, arg);
-}
-
-void InputBufferManager::_onBufferDestroyed(const C2Buffer* buf, void* arg) {
-    if (!buf || !arg) {
-        ALOGW("InputBufferManager::_onBufferDestroyed called "
-              "with null argument(s) (buf @ %p, arg @ %p)",
-              buf, arg);
-        return;
-    }
-    TrackedBuffer id(*reinterpret_cast<TrackedBuffer*>(arg));
-    ALOGV("InputBufferManager::_onBufferDestroyed called "
-          "(listener @ %p, frameIndex = %llu, bufferIndex = %zu)",
-          id.listener.unsafe_get(),
-          static_cast<unsigned long long>(id.frameIndex),
-          id.bufferIndex);
-
-    std::lock_guard<std::mutex> lock(mMutex);
-
-    auto findListener = mTrackedBuffersMap.find(id.listener);
-    if (findListener == mTrackedBuffersMap.end()) {
-        ALOGD("InputBufferManager::_onBufferDestroyed received "
-              "invalid listener "
-              "(listener @ %p, frameIndex = %llu, bufferIndex = %zu)",
-              id.listener.unsafe_get(),
-              static_cast<unsigned long long>(id.frameIndex),
-              id.bufferIndex);
-        return;
-    }
-
-    std::map<uint64_t, std::set<TrackedBuffer>> &frameIndex2BufferIds
-            = findListener->second;
-    auto findFrameIndex = frameIndex2BufferIds.find(id.frameIndex);
-    if (findFrameIndex == frameIndex2BufferIds.end()) {
-        ALOGD("InputBufferManager::_onBufferDestroyed received "
-              "invalid frame index "
-              "(listener @ %p, frameIndex = %llu, bufferIndex = %zu)",
-              id.listener.unsafe_get(),
-              static_cast<unsigned long long>(id.frameIndex),
-              id.bufferIndex);
-        return;
-    }
-
-    std::set<TrackedBuffer> &bufferIds = findFrameIndex->second;
-    auto findBufferId = bufferIds.find(id);
-    if (findBufferId == bufferIds.end()) {
-        ALOGD("InputBufferManager::_onBufferDestroyed received "
-              "invalid buffer index: "
-              "(listener @ %p, frameIndex = %llu, bufferIndex = %zu)",
-              id.listener.unsafe_get(),
-              static_cast<unsigned long long>(id.frameIndex),
-              id.bufferIndex);
-    }
-
-    bufferIds.erase(findBufferId);
-    if (bufferIds.empty()) {
-        frameIndex2BufferIds.erase(findFrameIndex);
-        if (frameIndex2BufferIds.empty()) {
-            mTrackedBuffersMap.erase(findListener);
-        }
-    }
-
-    DeathNotifications &deathNotifications = mDeathNotifications[id.listener];
-    deathNotifications.indices[id.frameIndex].emplace_back(id.bufferIndex);
-    ++deathNotifications.count;
-    mOnBufferDestroyed.notify_one();
-}
-
-// Notify the clients about buffer destructions.
-// Return false if all destructions have been notified.
-// Return true and set timeToRetry to the time point to wait for before
-// retrying if some destructions have not been notified.
-bool InputBufferManager::processNotifications(nsecs_t* timeToRetryNs) {
-
-    struct Notification {
-        sp<IComponentListener> listener;
-        hidl_vec<IComponentListener::RenderedFrame> renderedFrames;
-        Notification(const sp<IComponentListener>& l, size_t s)
-              : listener(l), renderedFrames(s) {}
-    };
-    std::list<Notification> notifications;
-
-    bool retry = false;
-    {
-        std::lock_guard<std::mutex> lock(mMutex);
-        *timeToRetryNs = kNotificationPeriodNs;
-        nsecs_t timeNowNs = systemTime();
-        for (auto it = mDeathNotifications.begin();
-                it != mDeathNotifications.end(); ) {
-            sp<IComponentListener> listener = it->first.promote();
-            if (!listener) {
-                ++it;
-                continue;
-            }
-            DeathNotifications &deathNotifications = it->second;
-
-            nsecs_t timeSinceLastNotifiedNs =
-                    timeNowNs - deathNotifications.lastSentNs;
-            // If not enough time has passed since the last callback, leave the
-            // notifications for this listener untouched for now and retry
-            // later.
-            if (timeSinceLastNotifiedNs < kNotificationPeriodNs) {
-                retry = true;
-                *timeToRetryNs = std::min(*timeToRetryNs,
-                        kNotificationPeriodNs - timeSinceLastNotifiedNs);
-                ALOGV("InputBufferManager: Notifications for "
-                      "listener @ %p will be postponed.",
-                      listener.get());
-                ++it;
-                continue;
-            }
-
-            // If enough time has passed since the last notification to this
-            // listener but there are currently no pending notifications, the
-            // listener can be removed from mDeathNotifications---there is no
-            // need to keep track of the last notification time anymore.
-            if (deathNotifications.count == 0) {
-                it = mDeathNotifications.erase(it);
-                continue;
-            }
-
-            // Create the argument for the callback.
-            notifications.emplace_back(listener, deathNotifications.count);
-            hidl_vec<IComponentListener::RenderedFrame>& renderedFrames =
-                    notifications.back().renderedFrames;
-            size_t i = 0;
-            for (std::pair<const uint64_t, std::vector<size_t>>& p :
-                    deathNotifications.indices) {
-                uint64_t frameIndex = p.first;
-                const std::vector<size_t> &bufferIndices = p.second;
-                for (const size_t& bufferIndex : bufferIndices) {
-                    IComponentListener::RenderedFrame &renderedFrame
-                            = renderedFrames[i++];
-                    renderedFrame.slotId = ~bufferIndex;
-                    renderedFrame.bufferQueueId = frameIndex;
-                    renderedFrame.timestampNs = timeNowNs;
-                    ALOGV("InputBufferManager: "
-                          "Sending death notification (listener @ %p, "
-                          "frameIndex = %llu, bufferIndex = %zu)",
-                          listener.get(),
-                          static_cast<long long unsigned>(frameIndex),
-                          bufferIndex);
-                }
-            }
-
-            // Clear deathNotifications for this listener and set retry to true
-            // so processNotifications will be called again. This will
-            // guarantee that a listener with no pending notifications will
-            // eventually be removed from mDeathNotifications after
-            // kNotificationPeriodNs nanoseconds has passed.
-            retry = true;
-            deathNotifications.indices.clear();
-            deathNotifications.count = 0;
-            deathNotifications.lastSentNs = timeNowNs;
-            ++it;
-        }
-    }
-
-    // Call onFramesRendered outside the lock to avoid deadlock.
-    for (const Notification& notification : notifications) {
-        if (!notification.listener->onFramesRendered(
-                notification.renderedFrames).isOk()) {
-            // This may trigger if the client has died.
-            ALOGD("InputBufferManager: onFramesRendered transaction failed "
-                  "(listener @ %p)",
-                  notification.listener.get());
-        }
-    }
-    if (retry) {
-        ALOGV("InputBufferManager: Pending death notifications"
-              "will be sent in %lldns.",
-              static_cast<long long>(*timeToRetryNs));
-    }
-    return retry;
-}
-
-void InputBufferManager::main() {
-    ALOGV("InputBufferManager: Starting main thread");
-    nsecs_t timeToRetryNs;
-    while (true) {
-        std::unique_lock<std::mutex> lock(mMutex);
-        while (mDeathNotifications.empty()) {
-            ALOGV("InputBufferManager: Waiting for buffer deaths");
-            mOnBufferDestroyed.wait(lock);
-        }
-        lock.unlock();
-        ALOGV("InputBufferManager: Sending buffer death notifications");
-        while (processNotifications(&timeToRetryNs)) {
-            std::this_thread::sleep_for(
-                    std::chrono::nanoseconds(timeToRetryNs));
-            ALOGV("InputBufferManager: Sending pending death notifications");
-        }
-        ALOGV("InputBufferManager: No pending death notifications");
-    }
-}
-
-InputBufferManager::InputBufferManager()
-      : mMainThread(&InputBufferManager::main, this) {
-}
-
-InputBufferManager& InputBufferManager::getInstance() {
-    static InputBufferManager instance{};
-    return instance;
+    mStore->reportComponentDeath(this);
 }
 
 }  // namespace utils
diff --git a/media/codec2/hidl/1.0/utils/ComponentInterface.cpp b/media/codec2/hidl/1.0/utils/ComponentInterface.cpp
new file mode 100644
index 0000000..39e5357
--- /dev/null
+++ b/media/codec2/hidl/1.0/utils/ComponentInterface.cpp
@@ -0,0 +1,110 @@
+/*
+ * 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 "Codec2-ComponentInterface"
+#include <android-base/logging.h>
+
+#include <codec2/hidl/1.0/Component.h>
+#include <codec2/hidl/1.0/ComponentInterface.h>
+#include <codec2/hidl/1.0/ComponentStore.h>
+
+#include <hidl/HidlBinderSupport.h>
+#include <utils/Timers.h>
+
+#include <C2BqBufferPriv.h>
+#include <C2Debug.h>
+#include <C2PlatformSupport.h>
+
+#include <chrono>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using namespace ::android;
+
+namespace /* unnamed */ {
+
+// Implementation of ConfigurableC2Intf based on C2ComponentInterface
+struct CompIntf : public ConfigurableC2Intf {
+    CompIntf(const std::shared_ptr<C2ComponentInterface>& intf) :
+        ConfigurableC2Intf{intf->getName(), intf->getId()},
+        mIntf{intf} {
+    }
+
+    virtual c2_status_t config(
+            const std::vector<C2Param*>& params,
+            c2_blocking_t mayBlock,
+            std::vector<std::unique_ptr<C2SettingResult>>* const failures
+            ) override {
+        return mIntf->config_vb(params, mayBlock, failures);
+    }
+
+    virtual c2_status_t query(
+            const std::vector<C2Param::Index>& indices,
+            c2_blocking_t mayBlock,
+            std::vector<std::unique_ptr<C2Param>>* const params
+            ) const override {
+        return mIntf->query_vb({}, indices, mayBlock, params);
+    }
+
+    virtual c2_status_t querySupportedParams(
+            std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
+            ) const override {
+        return mIntf->querySupportedParams_nb(params);
+    }
+
+    virtual c2_status_t querySupportedValues(
+            std::vector<C2FieldSupportedValuesQuery>& fields,
+            c2_blocking_t mayBlock) const override {
+        return mIntf->querySupportedValues_vb(fields, mayBlock);
+    }
+
+protected:
+    std::shared_ptr<C2ComponentInterface> mIntf;
+};
+
+} // unnamed namespace
+
+// ComponentInterface
+ComponentInterface::ComponentInterface(
+        const std::shared_ptr<C2ComponentInterface>& intf,
+        ComponentStore* store)
+      : mInterface{intf},
+        mConfigurable{new CachedConfigurable(std::make_unique<CompIntf>(intf))} {
+    mInit = mConfigurable->init(store);
+}
+
+c2_status_t ComponentInterface::status() const {
+    return mInit;
+}
+
+Return<sp<IConfigurable>> ComponentInterface::getConfigurable() {
+    return mConfigurable;
+}
+
+}  // namespace utils
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
diff --git a/media/codec2/hidl/1.0/utils/ComponentStore.cpp b/media/codec2/hidl/1.0/utils/ComponentStore.cpp
index 9c05014..bb5faa5 100644
--- a/media/codec2/hidl/1.0/utils/ComponentStore.cpp
+++ b/media/codec2/hidl/1.0/utils/ComponentStore.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -16,37 +16,25 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "Codec2-ComponentStore"
-#include <log/log.h>
+#include <android-base/logging.h>
 
 #include <codec2/hidl/1.0/ComponentStore.h>
 #include <codec2/hidl/1.0/InputSurface.h>
-#include <codec2/hidl/1.0/Component.h>
-#include <codec2/hidl/1.0/ConfigurableC2Intf.h>
 #include <codec2/hidl/1.0/types.h>
 
+#include <android-base/file.h>
 #include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
 #include <media/stagefright/bqhelper/GraphicBufferSource.h>
+#include <utils/Errors.h>
 
 #include <C2PlatformSupport.h>
 #include <util/C2InterfaceHelper.h>
 
-#include <utils/Errors.h>
-
-#include <android-base/file.h>
-
-#ifdef LOG
-#undef LOG
-#endif
-
-#ifdef PLOG
-#undef PLOG
-#endif
-
-#include <android-base/logging.h>
-
+#include <chrono>
+#include <ctime>
+#include <iomanip>
 #include <ostream>
 #include <sstream>
-#include <iomanip>
 
 namespace android {
 namespace hardware {
@@ -62,12 +50,12 @@
 namespace /* unnamed */ {
 
 struct StoreIntf : public ConfigurableC2Intf {
-    StoreIntf(const std::shared_ptr<C2ComponentStore>& store) :
-        ConfigurableC2Intf(store ? store->getName() : ""),
-        mStore(store) {
+    StoreIntf(const std::shared_ptr<C2ComponentStore>& store)
+          : ConfigurableC2Intf{store ? store->getName() : "", 0},
+            mStore{store} {
     }
 
-    c2_status_t config(
+    virtual c2_status_t config(
             const std::vector<C2Param*> &params,
             c2_blocking_t mayBlock,
             std::vector<std::unique_ptr<C2SettingResult>> *const failures
@@ -80,7 +68,7 @@
         return mStore->config_sm(params, failures);
     }
 
-    c2_status_t query(
+    virtual c2_status_t query(
             const std::vector<C2Param::Index> &indices,
             c2_blocking_t mayBlock,
             std::vector<std::unique_ptr<C2Param>> *const params) const override {
@@ -92,13 +80,13 @@
         return mStore->query_sm({}, indices, params);
     }
 
-    c2_status_t querySupportedParams(
+    virtual c2_status_t querySupportedParams(
             std::vector<std::shared_ptr<C2ParamDescriptor>> *const params
             ) const override {
         return mStore->querySupportedParams_nb(params);
     }
 
-    c2_status_t querySupportedValues(
+    virtual c2_status_t querySupportedValues(
             std::vector<C2FieldSupportedValuesQuery> &fields,
             c2_blocking_t mayBlock) const override {
         // Assume all params are blocking
@@ -115,9 +103,9 @@
 
 } // unnamed namespace
 
-ComponentStore::ComponentStore(const std::shared_ptr<C2ComponentStore>& store) :
-    Configurable(new CachedConfigurable(std::make_unique<StoreIntf>(store))),
-    mStore(store) {
+ComponentStore::ComponentStore(const std::shared_ptr<C2ComponentStore>& store)
+      : mConfigurable{new CachedConfigurable(std::make_unique<StoreIntf>(store))},
+        mStore{store} {
 
     std::shared_ptr<C2ComponentStore> platformStore = android::GetCodec2PlatformComponentStore();
     SetPreferredCodec2ComponentStore(store);
@@ -126,7 +114,11 @@
     mParamReflector = mStore->getParamReflector();
 
     // Retrieve supported parameters from store
-    mInit = init(this);
+    mInit = mConfigurable->init(this);
+}
+
+c2_status_t ComponentStore::status() const {
+    return mInit;
 }
 
 c2_status_t ComponentStore::validateSupportedParams(
@@ -172,19 +164,15 @@
         component = new Component(c2component, listener, this, pool);
         if (!component) {
             status = Status::CORRUPTED;
-        } else if (component->status() != C2_OK) {
-            status = static_cast<Status>(component->status());
         } else {
-            component->initListener(component);
+            reportComponentBirth(component.get());
             if (component->status() != C2_OK) {
                 status = static_cast<Status>(component->status());
             } else {
-                std::lock_guard<std::mutex> lock(mComponentRosterMutex);
-                component->setLocalId(
-                        mComponentRoster.emplace(
-                            Component::InterfaceKey(component),
-                            c2component)
-                        .first);
+                component->initListener(component);
+                if (component->status() != C2_OK) {
+                    status = static_cast<Status>(component->status());
+                }
             }
         }
     }
@@ -202,7 +190,7 @@
         onInterfaceLoaded(c2interface);
         interface = new ComponentInterface(c2interface, this);
     }
-    _hidl_cb((Status)res, interface);
+    _hidl_cb(static_cast<Status>(res), interface);
     return Void();
 }
 
@@ -213,27 +201,35 @@
     size_t ix = 0;
     for (const std::shared_ptr<const C2Component::Traits> &c2trait : c2traits) {
         if (c2trait) {
-            objcpy(&traits[ix++], *c2trait);
+            if (objcpy(&traits[ix], *c2trait)) {
+                ++ix;
+            } else {
+                break;
+            }
         }
     }
     traits.resize(ix);
-    _hidl_cb(traits);
+    _hidl_cb(Status::OK, traits);
     return Void();
 }
 
-Return<sp<IInputSurface>> ComponentStore::createInputSurface() {
+Return<void> ComponentStore::createInputSurface(createInputSurface_cb _hidl_cb) {
     sp<GraphicBufferSource> source = new GraphicBufferSource();
     if (source->initCheck() != OK) {
-        return nullptr;
+        _hidl_cb(Status::CORRUPTED, nullptr);
+        return Void();
     }
     typedef ::android::hardware::graphics::bufferqueue::V1_0::
             IGraphicBufferProducer HGbp;
     typedef ::android::TWGraphicBufferProducer<HGbp> B2HGbp;
-    return new InputSurface(
+    sp<InputSurface> inputSurface = new InputSurface(
             this,
             std::make_shared<C2ReflectorHelper>(),
             new B2HGbp(source->getIGraphicBufferProducer()),
             source);
+    _hidl_cb(inputSurface ? Status::OK : Status::NO_MEMORY,
+             inputSurface);
+    return Void();
 }
 
 void ComponentStore::onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf) {
@@ -265,15 +261,25 @@
                     mUnsupportedStructDescriptors.emplace(coreIndex);
                 } else {
                     mStructDescriptors.insert({ coreIndex, structDesc });
-                    objcpy(&descriptors[dstIx++], *structDesc);
-                    continue;
+                    if (objcpy(&descriptors[dstIx], *structDesc)) {
+                        ++dstIx;
+                        continue;
+                    }
+                    res = Status::CORRUPTED;
+                    break;
                 }
             }
             res = Status::NOT_FOUND;
         } else if (item->second) {
-            objcpy(&descriptors[dstIx++], *item->second);
+            if (objcpy(&descriptors[dstIx], *item->second)) {
+                ++dstIx;
+                continue;
+            }
+            res = Status::CORRUPTED;
+            break;
         } else {
             res = Status::NO_MEMORY;
+            break;
         }
     }
     descriptors.resize(dstIx);
@@ -292,29 +298,29 @@
     return Status::OMITTED;
 }
 
-void ComponentStore::reportComponentDeath(
-        const Component::LocalId& componentLocalId) {
-    std::lock_guard<std::mutex> lock(mComponentRosterMutex);
-    mComponentRoster.erase(componentLocalId);
+Return<sp<IConfigurable>> ComponentStore::getConfigurable() {
+    return mConfigurable;
 }
 
-std::shared_ptr<C2Component> ComponentStore::findC2Component(
-        const sp<IComponent>& component) const {
+// Called from createComponent() after a successful creation of `component`.
+void ComponentStore::reportComponentBirth(Component* component) {
+    ComponentStatus componentStatus;
+    componentStatus.c2Component = component->mComponent;
+    componentStatus.birthTime = std::chrono::system_clock::now();
+
     std::lock_guard<std::mutex> lock(mComponentRosterMutex);
-    Component::LocalId it = mComponentRoster.find(
-            Component::InterfaceKey(component));
-    if (it == mComponentRoster.end()) {
-        return std::shared_ptr<C2Component>();
-    }
-    return it->second.lock();
+    mComponentRoster.emplace(component, componentStatus);
 }
 
-// Debug dump
+// Called from within the destructor of `component`. No virtual function calls
+// are made on `component` here.
+void ComponentStore::reportComponentDeath(Component* component) {
+    std::lock_guard<std::mutex> lock(mComponentRosterMutex);
+    mComponentRoster.erase(component);
+}
 
-namespace /* unnamed */ {
-
-// Dump component traits
-std::ostream& dump(
+// Dumps component traits.
+std::ostream& ComponentStore::dump(
         std::ostream& out,
         const std::shared_ptr<const C2Component::Traits>& comp) {
 
@@ -334,25 +340,38 @@
     return out;
 }
 
-// Dump component
-std::ostream& dump(
+// Dumps component status.
+std::ostream& ComponentStore::dump(
         std::ostream& out,
-        const std::shared_ptr<C2Component>& comp) {
+        ComponentStatus& compStatus) {
 
     constexpr const char indent[] = "    ";
 
-    std::shared_ptr<C2ComponentInterface> intf = comp->intf();
+    // Print birth time.
+    std::chrono::milliseconds ms =
+            std::chrono::duration_cast<std::chrono::milliseconds>(
+                compStatus.birthTime.time_since_epoch());
+    std::time_t birthTime = std::chrono::system_clock::to_time_t(
+            compStatus.birthTime);
+    std::tm tm = *std::localtime(&birthTime);
+    out << indent << "Creation time: "
+        << std::put_time(&tm, "%Y-%m-%d %H:%M:%S")
+        << '.' << std::setfill('0') << std::setw(3) << ms.count() % 1000
+        << std::endl;
+
+    // Print name and id.
+    std::shared_ptr<C2ComponentInterface> intf = compStatus.c2Component->intf();
     if (!intf) {
-        out << indent << "Unknown -- null interface" << std::endl;
+        out << indent << "Unknown component -- null interface" << std::endl;
         return out;
     }
-    out << indent << "name: " << intf->getName() << std::endl;
-    out << indent << "id: " << intf->getId() << std::endl;
+    out << indent << "Name: " << intf->getName() << std::endl;
+    out << indent << "Id: " << intf->getId() << std::endl;
+
     return out;
 }
 
-} // unnamed namespace
-
+// Dumps information when lshal is called.
 Return<void> ComponentStore::debug(
         const hidl_handle& handle,
         const hidl_vec<hidl_string>& /* args */) {
@@ -387,31 +406,16 @@
             }
         }
 
-        // Retrieve the list of active components.
-        std::list<std::shared_ptr<C2Component>> activeComps;
-        {
-            std::lock_guard<std::mutex> lock(mComponentRosterMutex);
-            auto i = mComponentRoster.begin();
-            while (i != mComponentRoster.end()) {
-                std::shared_ptr<C2Component> c2comp = i->second.lock();
-                if (!c2comp) {
-                    auto j = i;
-                    ++i;
-                    mComponentRoster.erase(j);
-                } else {
-                    ++i;
-                    activeComps.emplace_back(c2comp);
-                }
-            }
-        }
-
         // Dump active components.
-        out << indent << "Active components:" << std::endl << std::endl;
-        if (activeComps.size() == 0) {
-            out << indent << indent << "NONE" << std::endl << std::endl;
-        } else {
-            for (const std::shared_ptr<C2Component>& c2comp : activeComps) {
-                dump(out, c2comp) << std::endl;
+        {
+            out << indent << "Active components:" << std::endl << std::endl;
+            std::lock_guard<std::mutex> lock(mComponentRosterMutex);
+            if (mComponentRoster.size() == 0) {
+                out << indent << indent << "NONE" << std::endl << std::endl;
+            } else {
+                for (auto& pair : mComponentRoster) {
+                    dump(out, pair.second) << std::endl;
+                }
             }
         }
 
diff --git a/media/codec2/hidl/1.0/utils/Configurable.cpp b/media/codec2/hidl/1.0/utils/Configurable.cpp
index d023ba8..a35b74c 100644
--- a/media/codec2/hidl/1.0/utils/Configurable.cpp
+++ b/media/codec2/hidl/1.0/utils/Configurable.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -16,11 +16,12 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "Codec2-Configurable"
-#include <log/log.h>
+#include <android-base/logging.h>
 
 #include <codec2/hidl/1.0/Configurable.h>
 #include <codec2/hidl/1.0/ComponentStore.h>
 #include <codec2/hidl/1.0/types.h>
+
 #include <C2ParamInternal.h>
 
 namespace android {
@@ -33,8 +34,8 @@
 using namespace ::android;
 
 CachedConfigurable::CachedConfigurable(
-        std::unique_ptr<ConfigurableC2Intf>&& intf) :
-    mIntf(std::move(intf)) {
+        std::unique_ptr<ConfigurableC2Intf>&& intf)
+      : mIntf{std::move(intf)} {
 }
 
 c2_status_t CachedConfigurable::init(ComponentStore* store) {
@@ -45,6 +46,10 @@
 }
 
 // Methods from ::android::hardware::media::c2::V1_0::IConfigurable follow.
+Return<uint32_t> CachedConfigurable::getId() {
+    return mIntf->getId();
+}
+
 Return<void> CachedConfigurable::getName(getName_cb _hidl_cb) {
     _hidl_cb(mIntf->getName());
     return Void();
@@ -65,9 +70,10 @@
             &c2heapParams);
 
     hidl_vec<uint8_t> params;
-    createParamsBlob(&params, c2heapParams);
+    if (!createParamsBlob(&params, c2heapParams)) {
+        LOG(WARNING) << "query -- invalid output params.";
+    }
     _hidl_cb(static_cast<Status>(c2res), params);
-
     return Void();
 }
 
@@ -78,7 +84,8 @@
     // inParams is not writable, so create a copy as config modifies the parameters
     hidl_vec<uint8_t> inParamsCopy = inParams;
     std::vector<C2Param*> c2params;
-    if (parseParamsBlob(&c2params, inParamsCopy) != C2_OK) {
+    if (!parseParamsBlob(&c2params, inParamsCopy)) {
+        LOG(WARNING) << "config -- invalid input params.";
         _hidl_cb(Status::CORRUPTED,
                 hidl_vec<SettingResult>(),
                 hidl_vec<uint8_t>());
@@ -95,13 +102,20 @@
         size_t ix = 0;
         for (const std::unique_ptr<C2SettingResult>& c2result : c2failures) {
             if (c2result) {
-                objcpy(&failures[ix++], *c2result);
+                if (objcpy(&failures[ix], *c2result)) {
+                    ++ix;
+                } else {
+                    LOG(DEBUG) << "config -- invalid setting results.";
+                    break;
+                }
             }
         }
         failures.resize(ix);
     }
     hidl_vec<uint8_t> outParams;
-    createParamsBlob(&outParams, c2params);
+    if (!createParamsBlob(&outParams, c2params)) {
+        LOG(DEBUG) << "config -- invalid output params.";
+    }
     _hidl_cb((Status)c2res, failures, outParams);
     return Void();
 }
@@ -117,7 +131,13 @@
     size_t dstIx = 0;
     for (size_t srcIx = request.offset(); srcIx < request.endOffset(); ++srcIx) {
         if (mSupportedParams[srcIx]) {
-            objcpy(&params[dstIx++], *mSupportedParams[srcIx]);
+            if (objcpy(&params[dstIx], *mSupportedParams[srcIx])) {
+                ++dstIx;
+            } else {
+                res = Status::CORRUPTED;
+                LOG(WARNING) << "querySupportedParams -- invalid output params.";
+                break;
+            }
         } else {
             res = Status::BAD_INDEX;
         }
@@ -154,7 +174,14 @@
     {
         size_t ix = 0;
         for (const C2FieldSupportedValuesQuery &result : c2fields) {
-            objcpy(&outFields[ix++], result);
+            if (!objcpy(&outFields[ix], result)) {
+                ++ix;
+            } else {
+                outFields.resize(ix);
+                c2res = C2_CORRUPTED;
+                LOG(WARNING) << "querySupportedValues -- invalid output params.";
+                break;
+            }
         }
     }
     _hidl_cb((Status)c2res, outFields);
diff --git a/media/codec2/hidl/1.0/utils/InputBufferManager.cpp b/media/codec2/hidl/1.0/utils/InputBufferManager.cpp
new file mode 100644
index 0000000..a023a05
--- /dev/null
+++ b/media/codec2/hidl/1.0/utils/InputBufferManager.cpp
@@ -0,0 +1,461 @@
+/*
+ * 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 "Codec2-InputBufferManager"
+#include <android-base/logging.h>
+
+#include <codec2/hidl/1.0/InputBufferManager.h>
+#include <codec2/hidl/1.0/types.h>
+
+#include <android/hardware/media/c2/1.0/IComponentListener.h>
+#include <android-base/logging.h>
+
+#include <C2Buffer.h>
+#include <C2Work.h>
+
+#include <chrono>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using namespace ::android;
+
+void InputBufferManager::registerFrameData(
+        const sp<IComponentListener>& listener,
+        const C2FrameData& input) {
+    getInstance()._registerFrameData(listener, input);
+}
+
+void InputBufferManager::unregisterFrameData(
+        const wp<IComponentListener>& listener,
+        const C2FrameData& input) {
+    getInstance()._unregisterFrameData(listener, input);
+}
+
+void InputBufferManager::unregisterFrameData(
+        const wp<IComponentListener>& listener) {
+    getInstance()._unregisterFrameData(listener);
+}
+
+void InputBufferManager::setNotificationInterval(
+        nsecs_t notificationIntervalNs) {
+    getInstance()._setNotificationInterval(notificationIntervalNs);
+}
+
+void InputBufferManager::_registerFrameData(
+        const sp<IComponentListener>& listener,
+        const C2FrameData& input) {
+    uint64_t frameIndex = input.ordinal.frameIndex.peeku();
+    LOG(VERBOSE) << "InputBufferManager::_registerFrameData -- called with "
+                 << "listener @ 0x" << std::hex << listener.get()
+                 << ", frameIndex = " << std::dec << frameIndex
+                 << ".";
+    std::lock_guard<std::mutex> lock(mMutex);
+
+    std::set<TrackedBuffer> &bufferIds =
+            mTrackedBuffersMap[listener][frameIndex];
+
+    for (size_t i = 0; i < input.buffers.size(); ++i) {
+        if (!input.buffers[i]) {
+            LOG(VERBOSE) << "InputBufferManager::_registerFrameData -- "
+                         << "Input buffer at index " << i << " is null.";
+            continue;
+        }
+        const TrackedBuffer &bufferId =
+                *bufferIds.emplace(listener, frameIndex, i, input.buffers[i]).
+                first;
+
+        c2_status_t status = input.buffers[i]->registerOnDestroyNotify(
+                onBufferDestroyed,
+                const_cast<void*>(reinterpret_cast<const void*>(&bufferId)));
+        if (status != C2_OK) {
+            LOG(DEBUG) << "InputBufferManager::_registerFrameData -- "
+                       << "registerOnDestroyNotify() failed "
+                       << "(listener @ 0x" << std::hex << listener.get()
+                       << ", frameIndex = " << std::dec << frameIndex
+                       << ", bufferIndex = " << i
+                       << ") => status = " << status
+                       << ".";
+        }
+    }
+
+    mDeathNotifications.emplace(
+            listener,
+            DeathNotifications(
+                mNotificationIntervalNs.load(std::memory_order_relaxed)));
+}
+
+// Remove a pair (listener, frameIndex) from mTrackedBuffersMap and
+// mDeathNotifications. This implies all bufferIndices are removed.
+//
+// This is called from onWorkDone() and flush().
+void InputBufferManager::_unregisterFrameData(
+        const wp<IComponentListener>& listener,
+        const C2FrameData& input) {
+    uint64_t frameIndex = input.ordinal.frameIndex.peeku();
+    LOG(VERBOSE) << "InputBufferManager::_unregisterFrameData -- called with "
+                 << "listener @ 0x" << std::hex << listener.unsafe_get()
+                 << ", frameIndex = " << std::dec << frameIndex
+                 << ".";
+    std::lock_guard<std::mutex> lock(mMutex);
+
+    auto findListener = mTrackedBuffersMap.find(listener);
+    if (findListener != mTrackedBuffersMap.end()) {
+        std::map<uint64_t, std::set<TrackedBuffer>> &frameIndex2BufferIds
+                = findListener->second;
+        auto findFrameIndex = frameIndex2BufferIds.find(frameIndex);
+        if (findFrameIndex != frameIndex2BufferIds.end()) {
+            std::set<TrackedBuffer> &bufferIds = findFrameIndex->second;
+            for (const TrackedBuffer& bufferId : bufferIds) {
+                std::shared_ptr<C2Buffer> buffer = bufferId.buffer.lock();
+                if (buffer) {
+                    c2_status_t status = buffer->unregisterOnDestroyNotify(
+                            onBufferDestroyed,
+                            const_cast<void*>(
+                            reinterpret_cast<const void*>(&bufferId)));
+                    if (status != C2_OK) {
+                        LOG(DEBUG) << "InputBufferManager::_unregisterFrameData "
+                                   << "-- unregisterOnDestroyNotify() failed "
+                                   << "(listener @ 0x"
+                                        << std::hex
+                                        << bufferId.listener.unsafe_get()
+                                   << ", frameIndex = "
+                                        << std::dec << bufferId.frameIndex
+                                   << ", bufferIndex = " << bufferId.bufferIndex
+                                   << ") => status = " << status
+                                   << ".";
+                    }
+                }
+            }
+
+            frameIndex2BufferIds.erase(findFrameIndex);
+            if (frameIndex2BufferIds.empty()) {
+                mTrackedBuffersMap.erase(findListener);
+            }
+        }
+    }
+
+    auto findListenerD = mDeathNotifications.find(listener);
+    if (findListenerD != mDeathNotifications.end()) {
+        DeathNotifications &deathNotifications = findListenerD->second;
+        auto findFrameIndex = deathNotifications.indices.find(frameIndex);
+        if (findFrameIndex != deathNotifications.indices.end()) {
+            std::vector<size_t> &bufferIndices = findFrameIndex->second;
+            deathNotifications.count -= bufferIndices.size();
+            deathNotifications.indices.erase(findFrameIndex);
+        }
+    }
+}
+
+// Remove listener from mTrackedBuffersMap and mDeathNotifications. This implies
+// all frameIndices and bufferIndices are removed.
+//
+// This is called when the component cleans up all input buffers, i.e., when
+// reset(), release(), stop() or ~Component() is called.
+void InputBufferManager::_unregisterFrameData(
+        const wp<IComponentListener>& listener) {
+    LOG(VERBOSE) << "InputBufferManager::_unregisterFrameData -- called with "
+                 << "listener @ 0x" << std::hex << listener.unsafe_get()
+                 << std::dec << ".";
+    std::lock_guard<std::mutex> lock(mMutex);
+
+    auto findListener = mTrackedBuffersMap.find(listener);
+    if (findListener != mTrackedBuffersMap.end()) {
+        std::map<uint64_t, std::set<TrackedBuffer>> &frameIndex2BufferIds =
+                findListener->second;
+        for (auto findFrameIndex = frameIndex2BufferIds.begin();
+                findFrameIndex != frameIndex2BufferIds.end();
+                ++findFrameIndex) {
+            std::set<TrackedBuffer> &bufferIds = findFrameIndex->second;
+            for (const TrackedBuffer& bufferId : bufferIds) {
+                std::shared_ptr<C2Buffer> buffer = bufferId.buffer.lock();
+                if (buffer) {
+                    c2_status_t status = buffer->unregisterOnDestroyNotify(
+                            onBufferDestroyed,
+                            const_cast<void*>(
+                            reinterpret_cast<const void*>(&bufferId)));
+                    if (status != C2_OK) {
+                        LOG(DEBUG) << "InputBufferManager::_unregisterFrameData "
+                                   << "-- unregisterOnDestroyNotify() failed "
+                                   << "(listener @ 0x"
+                                        << std::hex
+                                        << bufferId.listener.unsafe_get()
+                                   << ", frameIndex = "
+                                        << std::dec << bufferId.frameIndex
+                                   << ", bufferIndex = " << bufferId.bufferIndex
+                                   << ") => status = " << status
+                                   << ".";
+                    }
+                }
+            }
+        }
+        mTrackedBuffersMap.erase(findListener);
+    }
+
+    mDeathNotifications.erase(listener);
+}
+
+// Set mNotificationIntervalNs.
+void InputBufferManager::_setNotificationInterval(
+        nsecs_t notificationIntervalNs) {
+    mNotificationIntervalNs.store(
+            notificationIntervalNs,
+            std::memory_order_relaxed);
+}
+
+// Move a buffer from mTrackedBuffersMap to mDeathNotifications.
+// This is called when a registered C2Buffer object is destroyed.
+void InputBufferManager::onBufferDestroyed(const C2Buffer* buf, void* arg) {
+    getInstance()._onBufferDestroyed(buf, arg);
+}
+
+void InputBufferManager::_onBufferDestroyed(const C2Buffer* buf, void* arg) {
+    if (!buf || !arg) {
+        LOG(WARNING) << "InputBufferManager::_onBufferDestroyed -- called with "
+                     << "null argument (s): "
+                     << "buf @ 0x" << std::hex << buf
+                     << ", arg @ 0x" << std::hex << arg
+                     << std::dec << ".";
+        return;
+    }
+    TrackedBuffer id(*reinterpret_cast<TrackedBuffer*>(arg));
+    LOG(VERBOSE) << "InputBufferManager::_onBufferDestroyed -- called with "
+                 << "buf @ 0x" << std::hex << buf
+                 << ", arg @ 0x" << std::hex << arg
+                 << std::dec << " -- "
+                 << "listener @ 0x" << std::hex << id.listener.unsafe_get()
+                 << ", frameIndex = " << std::dec << id.frameIndex
+                 << ", bufferIndex = " << id.bufferIndex
+                 << ".";
+
+    std::lock_guard<std::mutex> lock(mMutex);
+
+    auto findListener = mTrackedBuffersMap.find(id.listener);
+    if (findListener == mTrackedBuffersMap.end()) {
+        LOG(DEBUG) << "InputBufferManager::_onBufferDestroyed -- "
+                   << "received invalid listener: "
+                   << "listener @ 0x" << std::hex << id.listener.unsafe_get()
+                   << " (frameIndex = " << std::dec << id.frameIndex
+                   << ", bufferIndex = " << id.bufferIndex
+                   << ").";
+        return;
+    }
+
+    std::map<uint64_t, std::set<TrackedBuffer>> &frameIndex2BufferIds
+            = findListener->second;
+    auto findFrameIndex = frameIndex2BufferIds.find(id.frameIndex);
+    if (findFrameIndex == frameIndex2BufferIds.end()) {
+        LOG(DEBUG) << "InputBufferManager::_onBufferDestroyed -- "
+                   << "received invalid frame index: "
+                   << "frameIndex = " << id.frameIndex
+                   << " (listener @ 0x" << std::hex << id.listener.unsafe_get()
+                   << ", bufferIndex = " << std::dec << id.bufferIndex
+                   << ").";
+        return;
+    }
+
+    std::set<TrackedBuffer> &bufferIds = findFrameIndex->second;
+    auto findBufferId = bufferIds.find(id);
+    if (findBufferId == bufferIds.end()) {
+        LOG(DEBUG) << "InputBufferManager::_onBufferDestroyed -- "
+                   << "received invalid buffer index: "
+                   << "bufferIndex = " << id.bufferIndex
+                   << " (frameIndex = " << id.frameIndex
+                   << ", listener @ 0x" << std::hex << id.listener.unsafe_get()
+                   << std::dec << ").";
+        return;
+    }
+
+    bufferIds.erase(findBufferId);
+    if (bufferIds.empty()) {
+        frameIndex2BufferIds.erase(findFrameIndex);
+        if (frameIndex2BufferIds.empty()) {
+            mTrackedBuffersMap.erase(findListener);
+        }
+    }
+
+    DeathNotifications &deathNotifications = mDeathNotifications[id.listener];
+    deathNotifications.indices[id.frameIndex].emplace_back(id.bufferIndex);
+    ++deathNotifications.count;
+    mOnBufferDestroyed.notify_one();
+}
+
+// Notify the clients about buffer destructions.
+// Return false if all destructions have been notified.
+// Return true and set timeToRetry to the time point to wait for before
+// retrying if some destructions have not been notified.
+bool InputBufferManager::processNotifications(nsecs_t* timeToRetryNs) {
+
+    struct Notification {
+        sp<IComponentListener> listener;
+        hidl_vec<IComponentListener::InputBuffer> inputBuffers;
+        Notification(const sp<IComponentListener>& l, size_t s)
+              : listener(l), inputBuffers(s) {}
+    };
+    std::list<Notification> notifications;
+    nsecs_t notificationIntervalNs =
+            mNotificationIntervalNs.load(std::memory_order_relaxed);
+
+    bool retry = false;
+    {
+        std::lock_guard<std::mutex> lock(mMutex);
+        *timeToRetryNs = notificationIntervalNs;
+        nsecs_t timeNowNs = systemTime();
+        for (auto it = mDeathNotifications.begin();
+                it != mDeathNotifications.end(); ) {
+            sp<IComponentListener> listener = it->first.promote();
+            if (!listener) {
+                ++it;
+                continue;
+            }
+            DeathNotifications &deathNotifications = it->second;
+
+            nsecs_t timeSinceLastNotifiedNs =
+                    timeNowNs - deathNotifications.lastSentNs;
+            // If not enough time has passed since the last callback, leave the
+            // notifications for this listener untouched for now and retry
+            // later.
+            if (timeSinceLastNotifiedNs < notificationIntervalNs) {
+                retry = true;
+                *timeToRetryNs = std::min(*timeToRetryNs,
+                        notificationIntervalNs - timeSinceLastNotifiedNs);
+                LOG(VERBOSE) << "InputBufferManager::processNotifications -- "
+                             << "Notifications for listener @ "
+                                 << std::hex << listener.get()
+                             << " will be postponed.";
+                ++it;
+                continue;
+            }
+
+            // If enough time has passed since the last notification to this
+            // listener but there are currently no pending notifications, the
+            // listener can be removed from mDeathNotifications---there is no
+            // need to keep track of the last notification time anymore.
+            if (deathNotifications.count == 0) {
+                it = mDeathNotifications.erase(it);
+                continue;
+            }
+
+            // Create the argument for the callback.
+            notifications.emplace_back(listener, deathNotifications.count);
+            hidl_vec<IComponentListener::InputBuffer> &inputBuffers =
+                    notifications.back().inputBuffers;
+            size_t i = 0;
+            for (std::pair<const uint64_t, std::vector<size_t>>& p :
+                    deathNotifications.indices) {
+                uint64_t frameIndex = p.first;
+                const std::vector<size_t> &bufferIndices = p.second;
+                for (const size_t& bufferIndex : bufferIndices) {
+                    IComponentListener::InputBuffer &inputBuffer
+                            = inputBuffers[i++];
+                    inputBuffer.arrayIndex = bufferIndex;
+                    inputBuffer.frameIndex = frameIndex;
+                }
+            }
+
+            // Clear deathNotifications for this listener and set retry to true
+            // so processNotifications will be called again. This will
+            // guarantee that a listener with no pending notifications will
+            // eventually be removed from mDeathNotifications after
+            // mNotificationIntervalNs nanoseconds has passed.
+            retry = true;
+            deathNotifications.indices.clear();
+            deathNotifications.count = 0;
+            deathNotifications.lastSentNs = timeNowNs;
+            ++it;
+        }
+    }
+
+    // Call onInputBuffersReleased() outside the lock to avoid deadlock.
+    for (const Notification& notification : notifications) {
+        if (!notification.listener->onInputBuffersReleased(
+                notification.inputBuffers).isOk()) {
+            // This may trigger if the client has died.
+            LOG(DEBUG) << "InputBufferManager::processNotifications -- "
+                       << "failed to send death notifications to "
+                       << "listener @ 0x" << std::hex
+                                          << notification.listener.get()
+                       << std::dec << ".";
+        } else {
+#if LOG_NDEBUG == 0
+            std::stringstream inputBufferLog;
+            for (const IComponentListener::InputBuffer& inputBuffer :
+                    notification.inputBuffers) {
+                inputBufferLog << " (" << inputBuffer.frameIndex
+                               << ", " << inputBuffer.arrayIndex
+                               << ")";
+            }
+            LOG(VERBOSE) << "InputBufferManager::processNotifications -- "
+                         << "death notifications sent to "
+                         << "listener @ 0x" << std::hex
+                                            << notification.listener.get()
+                                            << std::dec
+                         << " with these (frameIndex, bufferIndex) pairs:"
+                         << inputBufferLog.str();
+#endif
+        }
+    }
+#if LOG_NDEBUG == 0
+    if (retry) {
+        LOG(VERBOSE) << "InputBufferManager::processNotifications -- "
+                     << "will retry again in " << *timeToRetryNs << "ns.";
+    } else {
+        LOG(VERBOSE) << "InputBufferManager::processNotifications -- "
+                     << "no pending death notifications.";
+    }
+#endif
+    return retry;
+}
+
+void InputBufferManager::main() {
+    LOG(VERBOSE) << "InputBufferManager main -- started.";
+    nsecs_t timeToRetryNs;
+    while (true) {
+        std::unique_lock<std::mutex> lock(mMutex);
+        while (mDeathNotifications.empty()) {
+            mOnBufferDestroyed.wait(lock);
+        }
+        lock.unlock();
+        while (processNotifications(&timeToRetryNs)) {
+            std::this_thread::sleep_for(
+                    std::chrono::nanoseconds(timeToRetryNs));
+        }
+    }
+}
+
+InputBufferManager::InputBufferManager()
+      : mMainThread{&InputBufferManager::main, this} {
+}
+
+InputBufferManager& InputBufferManager::getInstance() {
+    static InputBufferManager instance{};
+    return instance;
+}
+
+}  // namespace utils
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+
+
diff --git a/media/codec2/hidl/1.0/utils/InputSurface.cpp b/media/codec2/hidl/1.0/utils/InputSurface.cpp
index b669460..2cbe64b 100644
--- a/media/codec2/hidl/1.0/utils/InputSurface.cpp
+++ b/media/codec2/hidl/1.0/utils/InputSurface.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -16,12 +16,11 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "Codec2-InputSurface"
-#include <log/log.h>
+#include <android-base/logging.h>
 
 #include <codec2/hidl/1.0/InputSurface.h>
 #include <codec2/hidl/1.0/InputSurfaceConnection.h>
 
-#include <util/C2InterfaceHelper.h>
 #include <C2Component.h>
 #include <C2Config.h>
 
@@ -36,9 +35,10 @@
 
 using namespace ::android;
 
-class InputSurface::ConfigurableImpl : public C2InterfaceHelper {
+// Derived class of C2InterfaceHelper
+class InputSurface::Interface : public C2InterfaceHelper {
 public:
-    explicit ConfigurableImpl(
+    explicit Interface(
             const std::shared_ptr<C2ReflectorHelper> &helper)
         : C2InterfaceHelper(helper) {
 
@@ -63,33 +63,34 @@
     std::shared_ptr<C2InputSurfaceEosTuning> mEos;
 };
 
-namespace {
-
-class ConfigurableWrapper : public ConfigurableC2Intf {
+// Derived class of ConfigurableC2Intf
+class InputSurface::ConfigurableIntf : public ConfigurableC2Intf {
 public:
-    ConfigurableWrapper(
-            const std::shared_ptr<InputSurface::ConfigurableImpl> &impl,
+    ConfigurableIntf(
+            const std::shared_ptr<InputSurface::Interface> &intf,
             const sp<GraphicBufferSource> &source)
-        : ConfigurableC2Intf("input-surface"),
-          mImpl(impl),
+        : ConfigurableC2Intf("input-surface", 0),
+          mIntf(intf),
           mSource(source) {
     }
 
-    ~ConfigurableWrapper() override = default;
+    virtual ~ConfigurableIntf() override = default;
 
-    c2_status_t query(
+    virtual c2_status_t query(
             const std::vector<C2Param::Index> &indices,
             c2_blocking_t mayBlock,
-            std::vector<std::unique_ptr<C2Param>>* const params) const override {
-        return mImpl->query({}, indices, mayBlock, params);
+            std::vector<std::unique_ptr<C2Param>>* const params
+            ) const override {
+        return mIntf->query({}, indices, mayBlock, params);
     }
 
-    c2_status_t config(
+    virtual c2_status_t config(
             const std::vector<C2Param*> &params,
             c2_blocking_t mayBlock,
-            std::vector<std::unique_ptr<C2SettingResult>>* const failures) override {
-        c2_status_t err = mImpl->config(params, mayBlock, failures);
-        if (mImpl->eos()) {
+            std::vector<std::unique_ptr<C2SettingResult>>* const failures
+            ) override {
+        c2_status_t err = mIntf->config(params, mayBlock, failures);
+        if (mIntf->eos()) {
             sp<GraphicBufferSource> source = mSource.promote();
             if (source == nullptr || source->signalEndOfInputStream() != OK) {
                 // TODO: put something in |failures|
@@ -100,202 +101,71 @@
         return err;
     }
 
-    c2_status_t querySupportedParams(
-            std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const override {
-        return mImpl->querySupportedParams(params);
+    virtual c2_status_t querySupportedParams(
+            std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
+            ) const override {
+        return mIntf->querySupportedParams(params);
     }
 
-    c2_status_t querySupportedValues(
+    virtual c2_status_t querySupportedValues(
             std::vector<C2FieldSupportedValuesQuery>& fields,
             c2_blocking_t mayBlock) const override {
-        return mImpl->querySupportedValues(fields, mayBlock);
+        return mIntf->querySupportedValues(fields, mayBlock);
     }
 
 private:
-    const std::shared_ptr<InputSurface::ConfigurableImpl> mImpl;
+    const std::shared_ptr<InputSurface::Interface> mIntf;
     wp<GraphicBufferSource> mSource;
 };
 
-}  // namespace
-
-
-Return<void> InputSurface::connectToComponent(
-        const sp<IComponent>& component,
-        connectToComponent_cb _hidl_cb) {
-    Status status;
-    sp<InputSurfaceConnection> conn;
-    if (!component) {
-        status = Status::BAD_VALUE;
-    } else {
-        std::shared_ptr<C2Component> comp = mStore->findC2Component(component);
-        if (!comp) {
-            conn = new InputSurfaceConnection(mSource, component);
-        } else {
-            conn = new InputSurfaceConnection(mSource, comp);
-        }
-        if (!conn->init()) {
-            conn = nullptr;
-            status = Status::BAD_VALUE;
-        } else {
-            status = Status::OK;
-        }
-    }
-    _hidl_cb(status, conn);
-    return Void();
+Return<sp<InputSurface::HGraphicBufferProducer>> InputSurface::getGraphicBufferProducer() {
+    return mProducer;
 }
 
 Return<sp<IConfigurable>> InputSurface::getConfigurable() {
     return mConfigurable;
 }
 
-// Derived methods from IGraphicBufferProducer
-
-Return<void> InputSurface::requestBuffer(
-        int32_t slot,
-        requestBuffer_cb _hidl_cb) {
-    return mBase->requestBuffer(slot, _hidl_cb);
-}
-
-Return<int32_t> InputSurface::setMaxDequeuedBufferCount(
-        int32_t maxDequeuedBuffers) {
-    return mBase->setMaxDequeuedBufferCount(maxDequeuedBuffers);
-}
-
-Return<int32_t> InputSurface::setAsyncMode(
-        bool async) {
-    return mBase->setAsyncMode(async);
-}
-
-Return<void> InputSurface::dequeueBuffer(
-        uint32_t width,
-        uint32_t height,
-        PixelFormat format,
-        uint32_t usage,
-        bool getFrameTimestamps,
-        dequeueBuffer_cb _hidl_cb) {
-    return mBase->dequeueBuffer(
-            width, height, format, usage, getFrameTimestamps, _hidl_cb);
-}
-
-Return<int32_t> InputSurface::detachBuffer(
-        int32_t slot) {
-    return mBase->detachBuffer(slot);
-}
-
-Return<void> InputSurface::detachNextBuffer(
-        detachNextBuffer_cb _hidl_cb) {
-    return mBase->detachNextBuffer(_hidl_cb);
-}
-
-Return<void> InputSurface::attachBuffer(
-        const AnwBuffer& buffer,
-        attachBuffer_cb _hidl_cb) {
-    return mBase->attachBuffer(buffer, _hidl_cb);
-}
-
-Return<void> InputSurface::queueBuffer(
-        int32_t slot,
-        const QueueBufferInput& input,
-        queueBuffer_cb _hidl_cb) {
-    return mBase->queueBuffer(slot, input, _hidl_cb);
-}
-
-Return<int32_t> InputSurface::cancelBuffer(
-        int32_t slot,
-        const hidl_handle& fence) {
-    return mBase->cancelBuffer(slot, fence);
-}
-
-Return<void> InputSurface::query(
-        int32_t what,
-        query_cb _hidl_cb) {
-    return mBase->query(what, _hidl_cb);
-}
-
 Return<void> InputSurface::connect(
-        const sp<HProducerListener>& listener,
-        int32_t api,
-        bool producerControlledByApp,
+        const sp<IInputSink>& sink,
         connect_cb _hidl_cb) {
-    return mBase->connect(listener, api, producerControlledByApp, _hidl_cb);
+    Status status;
+    sp<InputSurfaceConnection> connection;
+    if (!sink) {
+        _hidl_cb(Status::BAD_VALUE, nullptr);
+        return Void();
+    }
+    std::shared_ptr<C2Component> comp = Component::findLocalComponent(sink);
+    if (comp) {
+        connection = new InputSurfaceConnection(mSource, comp, mStore);
+    } else {
+        connection = new InputSurfaceConnection(mSource, sink, mStore);
+    }
+    if (!connection->init()) {
+        connection = nullptr;
+        status = Status::BAD_VALUE;
+    } else {
+        status = Status::OK;
+    }
+    _hidl_cb(status, connection);
+    return Void();
 }
 
-Return<int32_t> InputSurface::disconnect(
-        int32_t api,
-        DisconnectMode mode) {
-    return mBase->disconnect(api, mode);
-}
-
-Return<int32_t> InputSurface::setSidebandStream(
-        const hidl_handle& stream) {
-    return mBase->setSidebandStream(stream);
-}
-
-Return<void> InputSurface::allocateBuffers(
-        uint32_t width,
-        uint32_t height,
-        PixelFormat format,
-        uint32_t usage) {
-    return mBase->allocateBuffers(width, height, format, usage);
-}
-
-Return<int32_t> InputSurface::allowAllocation(
-        bool allow) {
-    return mBase->allowAllocation(allow);
-}
-
-Return<int32_t> InputSurface::setGenerationNumber(
-        uint32_t generationNumber) {
-    return mBase->setGenerationNumber(generationNumber);
-}
-
-Return<void> InputSurface::getConsumerName(
-        getConsumerName_cb _hidl_cb) {
-    return mBase->getConsumerName(_hidl_cb);
-}
-
-Return<int32_t> InputSurface::setSharedBufferMode(
-        bool sharedBufferMode) {
-    return mBase->setSharedBufferMode(sharedBufferMode);
-}
-
-Return<int32_t> InputSurface::setAutoRefresh(
-        bool autoRefresh) {
-    return mBase->setAutoRefresh(autoRefresh);
-}
-
-Return<int32_t> InputSurface::setDequeueTimeout(
-        int64_t timeoutNs) {
-    return mBase->setDequeueTimeout(timeoutNs);
-}
-
-Return<void> InputSurface::getLastQueuedBuffer(
-        getLastQueuedBuffer_cb _hidl_cb) {
-    return mBase->getLastQueuedBuffer(_hidl_cb);
-}
-
-Return<void> InputSurface::getFrameTimestamps(
-        getFrameTimestamps_cb _hidl_cb) {
-    return mBase->getFrameTimestamps(_hidl_cb);
-}
-
-Return<void> InputSurface::getUniqueId(
-        getUniqueId_cb _hidl_cb) {
-    return mBase->getUniqueId(_hidl_cb);
-}
+// Derived methods from IGraphicBufferProducer
 
 // Constructor is exclusive to ComponentStore.
 InputSurface::InputSurface(
         const sp<ComponentStore>& store,
         const std::shared_ptr<C2ReflectorHelper>& reflector,
-        const sp<HGraphicBufferProducer>& base,
-        const sp<GraphicBufferSource>& source) :
-    mStore(store),
-    mBase(base),
-    mSource(source),
-    mHelper(std::make_shared<ConfigurableImpl>(reflector)),
-    mConfigurable(new CachedConfigurable(
-            std::make_unique<ConfigurableWrapper>(mHelper, source))) {
+        const sp<HGraphicBufferProducer>& producer,
+        const sp<GraphicBufferSource>& source)
+      : mStore{store},
+        mProducer{producer},
+        mSource{source},
+        mIntf{std::make_shared<Interface>(reflector)},
+        mConfigurable{new CachedConfigurable(
+                std::make_unique<ConfigurableIntf>(
+                    mIntf, source))} {
 
     mConfigurable->init(store.get());
 }
diff --git a/media/codec2/hidl/1.0/utils/InputSurfaceConnection.cpp b/media/codec2/hidl/1.0/utils/InputSurfaceConnection.cpp
index 8b1ece3..1024f50 100644
--- a/media/codec2/hidl/1.0/utils/InputSurfaceConnection.cpp
+++ b/media/codec2/hidl/1.0/utils/InputSurfaceConnection.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -16,9 +16,10 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "Codec2-InputSurfaceConnection"
-#include <log/log.h>
+#include <android-base/logging.h>
 
 #include <codec2/hidl/1.0/InputSurfaceConnection.h>
+#include <codec2/hidl/1.0/InputSurfaceConnection.h>
 
 #include <memory>
 #include <list>
@@ -65,51 +66,74 @@
 
 } // unnamed namespace
 
+// Derived class of ComponentWrapper for use with
+// GraphicBufferSource::configure().
+//
 struct InputSurfaceConnection::Impl : public ComponentWrapper {
+
     Impl(const sp<GraphicBufferSource>& source,
-         const std::shared_ptr<C2Component>& comp) :
-            mSource(source), mComp(comp), mRemoteComp(),
-            mFrameIndex(0) {
-        std::shared_ptr<C2ComponentInterface> intf = comp->intf();
-        mCompName = intf ? intf->getName() : "";
+         const std::shared_ptr<C2Component>& localComp)
+          : mSource{source}, mLocalComp{localComp}, mSink{}, mFrameIndex{0} {
+        std::shared_ptr<C2ComponentInterface> intf = localComp->intf();
+        mSinkName = intf ? intf->getName() : "";
     }
 
     Impl(const sp<GraphicBufferSource>& source,
-         const sp<IComponent>& comp) :
-            mSource(source), mComp(), mRemoteComp(comp),
-            mFrameIndex(0) {
-        Return<void> transStatus = comp->getName(
-                [this](const hidl_string& name) {
-                    mCompName = name.c_str();
+         const sp<IInputSink>& sink)
+          : mSource{source}, mLocalComp{}, mSink{sink}, mFrameIndex{0} {
+        Return<sp<IConfigurable>> transResult = sink->getConfigurable();
+        if (!transResult.isOk()) {
+            LOG(ERROR) << "Remote sink is dead.";
+            return;
+        }
+        mSinkConfigurable =
+                static_cast<sp<IConfigurable>>(transResult);
+        if (!mSinkConfigurable) {
+            LOG(ERROR) << "Remote sink is not configurable.";
+            mSinkName = "";
+            return;
+        }
+
+        hidl_string name;
+        Return<void> transStatus = mSinkConfigurable->getName(
+                [&name](const hidl_string& n) {
+                    name = n;
                 });
         if (!transStatus.isOk()) {
-            ALOGD("getName -- Cannot obtain remote component name.");
+            LOG(ERROR) << "Remote sink's configurable is dead.";
+            mSinkName = "";
+            return;
         }
+        mSinkName = name.c_str();
     }
 
-    virtual ~Impl() = default;
+    virtual ~Impl() {
+        mSource->stop();
+        mSource->release();
+    }
 
     bool init() {
-        sp<GraphicBufferSource> source = mSource.promote();
-        if (source == nullptr) {
+        if (mSource == nullptr) {
             return false;
         }
-        status_t err = source->initCheck();
+        status_t err = mSource->initCheck();
         if (err != OK) {
-            ALOGD("Impl::init -- GBS init failed: %d", err);
+            LOG(WARNING) << "Impl::init -- GraphicBufferSource init failed: "
+                         << "status = " << err << ".";
             return false;
         }
 
         // TODO: read settings properly from the interface
         C2VideoSizeStreamTuning::input inputSize;
         C2StreamUsageTuning::input usage;
-        c2_status_t c2Status = compQuery({ &inputSize, &usage },
+        c2_status_t c2Status = queryFromSink({ &inputSize, &usage },
                                          {},
                                          C2_MAY_BLOCK,
                                          nullptr);
         if (c2Status != C2_OK) {
-            ALOGD("Impl::init -- cannot query information from "
-                    "the component interface: %s.", asString(c2Status));
+            LOG(WARNING) << "Impl::init -- cannot query information from "
+                            "the component interface: "
+                         << "status = " << asString(c2Status) << ".";
             return false;
         }
 
@@ -122,26 +146,27 @@
         //         asGrallocUsage();
 
         uint32_t grallocUsage =
-                mCompName.compare(0, 11, "c2.android.") == 0 ?
+                mSinkName.compare(0, 11, "c2.android.") == 0 ?
                 GRALLOC_USAGE_SW_READ_OFTEN :
                 GRALLOC_USAGE_HW_VIDEO_ENCODER;
 
-        err = source->configure(
+        err = mSource->configure(
                 this, dataSpace, kBufferCount,
                 inputSize.width, inputSize.height,
                 grallocUsage);
         if (err != OK) {
-            ALOGD("Impl::init -- GBS configure failed: %d", err);
+            LOG(WARNING) << "Impl::init -- GBS configure failed: "
+                         << "status = " << err << ".";
             return false;
         }
         for (int32_t i = 0; i < kBufferCount; ++i) {
-            if (!source->onInputBufferAdded(i).isOk()) {
-                ALOGD("Impl::init: populating GBS slots failed");
+            if (!mSource->onInputBufferAdded(i).isOk()) {
+                LOG(WARNING) << "Impl::init: failed to populate GBS slots.";
                 return false;
             }
         }
-        if (!source->start().isOk()) {
-            ALOGD("Impl::init -- GBS start failed");
+        if (!mSource->start().isOk()) {
+            LOG(WARNING) << "Impl::init -- GBS failed to start.";
             return false;
         }
         mAllocatorMutex.lock();
@@ -150,7 +175,8 @@
                 &mAllocator);
         mAllocatorMutex.unlock();
         if (c2err != OK) {
-            ALOGD("Impl::init -- failed to fetch gralloc allocator: %d", c2err);
+            LOG(WARNING) << "Impl::init -- failed to fetch gralloc allocator: "
+                         << "status = " << asString(c2err) << ".";
             return false;
         }
         return true;
@@ -162,7 +188,7 @@
             const sp<GraphicBuffer>& buffer,
             int64_t timestamp,
             int fenceFd) override {
-        ALOGV("Impl::submitBuffer -- bufferId = %d", bufferId);
+        LOG(VERBOSE) << "Impl::submitBuffer -- bufferId = " << bufferId << ".";
         // TODO: Use fd to construct fence
         (void)fenceFd;
 
@@ -190,9 +216,8 @@
                 // TODO: fence
                 new Buffer2D(block->share(
                         C2Rect(block->width(), block->height()), ::C2Fence())),
-                [bufferId, src = mSource](C2Buffer* ptr) {
+                [bufferId, source = mSource](C2Buffer* ptr) {
                     delete ptr;
-                    sp<GraphicBufferSource> source = src.promote();
                     if (source != nullptr) {
                         // TODO: fence
                         (void)source->onInputBufferEmptied(bufferId, -1);
@@ -204,12 +229,13 @@
         std::list<std::unique_ptr<C2Work>> items;
         items.push_back(std::move(work));
 
-        err = compQueue(&items);
+        err = queueToSink(&items);
         return (err == C2_OK) ? OK : UNKNOWN_ERROR;
     }
 
-    virtual status_t submitEos(int32_t /* bufferId */) override {
-        ALOGV("Impl::submitEos");
+    virtual status_t submitEos(int32_t bufferId) override {
+        LOG(VERBOSE) << "Impl::submitEos -- bufferId = " << bufferId << ".";
+        (void)bufferId;
 
         std::unique_ptr<C2Work> work(new C2Work);
         work->input.flags = (C2FrameData::flags_t)0;
@@ -221,11 +247,11 @@
         std::list<std::unique_ptr<C2Work>> items;
         items.push_back(std::move(work));
 
-        c2_status_t err = compQueue(&items);
+        c2_status_t err = queueToSink(&items);
         return (err == C2_OK) ? OK : UNKNOWN_ERROR;
     }
 
-    void dispatchDataSpaceChanged(
+    virtual void dispatchDataSpaceChanged(
             int32_t dataSpace, int32_t aspects, int32_t pixelFormat) override {
         // TODO
         (void)dataSpace;
@@ -233,36 +259,63 @@
         (void)pixelFormat;
     }
 
+    // Configurable interface for InputSurfaceConnection::Impl.
+    //
+    // This class is declared as an inner class so that it will have access to
+    // all Impl's members.
+    struct ConfigurableIntf : public ConfigurableC2Intf {
+        sp<Impl> mConnection;
+        ConfigurableIntf(const sp<Impl>& connection)
+              : ConfigurableC2Intf{"input-surface-connection", 0},
+                mConnection{connection} {}
+        virtual c2_status_t config(
+                const std::vector<C2Param*> &params,
+                c2_blocking_t mayBlock,
+                std::vector<std::unique_ptr<C2SettingResult>> *const failures
+                ) override;
+        virtual c2_status_t query(
+                const std::vector<C2Param::Index> &indices,
+                c2_blocking_t mayBlock,
+                std::vector<std::unique_ptr<C2Param>> *const params) const override;
+        virtual c2_status_t querySupportedParams(
+                std::vector<std::shared_ptr<C2ParamDescriptor>> *const params
+                ) const override;
+        virtual c2_status_t querySupportedValues(
+                std::vector<C2FieldSupportedValuesQuery> &fields,
+                c2_blocking_t mayBlock) const override;
+    };
+
 private:
-    c2_status_t compQuery(
+    c2_status_t queryFromSink(
             const std::vector<C2Param*> &stackParams,
             const std::vector<C2Param::Index> &heapParamIndices,
             c2_blocking_t mayBlock,
             std::vector<std::unique_ptr<C2Param>>* const heapParams) {
-        std::shared_ptr<C2Component> comp = mComp.lock();
-        if (comp) {
-            std::shared_ptr<C2ComponentInterface> intf = comp->intf();
+        if (mLocalComp) {
+            std::shared_ptr<C2ComponentInterface> intf = mLocalComp->intf();
             if (intf) {
                 return intf->query_vb(stackParams,
                                       heapParamIndices,
                                       mayBlock,
                                       heapParams);
             } else {
-                ALOGD("compQuery -- component does not have an interface.");
+                LOG(ERROR) << "queryFromSink -- "
+                           << "component does not have an interface.";
                 return C2_BAD_STATE;
             }
         }
-        if (!mRemoteComp) {
-            ALOGD("compQuery -- component no longer exists.");
-            return C2_BAD_STATE;
-        }
+
+        CHECK(mSink) << "-- queryFromSink "
+                     << "-- connection has no sink.";
+        CHECK(mSinkConfigurable) << "-- queryFromSink "
+                                 << "-- sink has no configurable.";
 
         hidl_vec<ParamIndex> indices(
                 stackParams.size() + heapParamIndices.size());
         size_t numIndices = 0;
         for (C2Param* const& stackParam : stackParams) {
             if (!stackParam) {
-                ALOGD("compQuery -- null stack param encountered.");
+                LOG(DEBUG) << "queryFromSink -- null stack param encountered.";
                 continue;
             }
             indices[numIndices++] = static_cast<ParamIndex>(stackParam->index());
@@ -277,22 +330,22 @@
             heapParams->reserve(heapParams->size() + numIndices);
         }
         c2_status_t status;
-        Return<void> transStatus = mRemoteComp->query(
+        Return<void> transStatus = mSinkConfigurable->query(
                 indices,
                 mayBlock == C2_MAY_BLOCK,
                 [&status, &numStackIndices, &stackParams, heapParams](
                         Status s, const Params& p) {
                     status = static_cast<c2_status_t>(s);
                     if (status != C2_OK && status != C2_BAD_INDEX) {
-                        ALOGD("compQuery -- call failed: %s.", asString(status));
+                        LOG(DEBUG) << "queryFromSink -- call failed: "
+                                   << "status = " << asString(status) << ".";
                         return;
                     }
                     std::vector<C2Param*> paramPointers;
-                    c2_status_t parseStatus = parseParamsBlob(&paramPointers, p);
-                    if (parseStatus != C2_OK) {
-                        ALOGD("compQuery -- error while parsing params: %s.",
-                              asString(parseStatus));
-                        status = parseStatus;
+                    if (!parseParamsBlob(&paramPointers, p)) {
+                        LOG(DEBUG) << "queryFromSink -- error while "
+                                   << "parsing params.";
+                        status = C2_CORRUPTED;
                         return;
                     }
                     size_t i = 0;
@@ -302,7 +355,8 @@
                         if (numStackIndices > 0) {
                             --numStackIndices;
                             if (!paramPointer) {
-                                ALOGD("compQuery -- null stack param.");
+                                LOG(DEBUG) << "queryFromSink -- "
+                                              "null stack param.";
                                 ++it;
                                 continue;
                             }
@@ -313,25 +367,27 @@
                             CHECK(i < stackParams.size());
                             if (stackParams[i]->index() !=
                                     paramPointer->index()) {
-                                ALOGD("compQuery -- param skipped. index = %d",
-                                      static_cast<int>(
-                                      stackParams[i]->index()));
+                                LOG(DEBUG) << "queryFromSink -- "
+                                              "param skipped (index = "
+                                           << stackParams[i]->index() << ").";
                                 stackParams[i++]->invalidate();
                                 continue;
                             }
                             if (!stackParams[i++]->updateFrom(*paramPointer)) {
-                                ALOGD("compQuery -- param update failed: "
-                                      "index = %d.",
-                                      static_cast<int>(paramPointer->index()));
+                                LOG(DEBUG) << "queryFromSink -- "
+                                              "param update failed (index = "
+                                           << paramPointer->index() << ").";
                             }
                         } else {
                             if (!paramPointer) {
-                                ALOGD("compQuery -- null heap param.");
+                                LOG(DEBUG) << "queryFromSink -- "
+                                              "null heap param.";
                                 ++it;
                                 continue;
                             }
                             if (!heapParams) {
-                                ALOGD("compQuery -- too many stack params.");
+                                LOG(WARNING) << "queryFromSink -- "
+                                                "too many stack params.";
                                 break;
                             }
                             heapParams->emplace_back(C2Param::Copy(*paramPointer));
@@ -340,96 +396,130 @@
                     }
                 });
         if (!transStatus.isOk()) {
-            ALOGD("compQuery -- transaction failed.");
+            LOG(ERROR) << "queryFromSink -- transaction failed.";
             return C2_CORRUPTED;
         }
         return status;
     }
 
-    c2_status_t compQueue(std::list<std::unique_ptr<C2Work>>* const items) {
-        std::shared_ptr<C2Component> comp = mComp.lock();
-        if (comp) {
-            return comp->queue_nb(items);
+    c2_status_t queueToSink(std::list<std::unique_ptr<C2Work>>* const items) {
+        if (mLocalComp) {
+            return mLocalComp->queue_nb(items);
         }
 
+        CHECK(mSink) << "-- queueToSink "
+                     << "-- connection has no sink.";
+
         WorkBundle workBundle;
-        Status hidlStatus = objcpy(&workBundle, *items, nullptr);
-        if (hidlStatus != Status::OK) {
-            ALOGD("compQueue -- bad input.");
+        if (!objcpy(&workBundle, *items, nullptr)) {
+            LOG(ERROR) << "queueToSink -- bad input.";
             return C2_CORRUPTED;
         }
-        Return<Status> transStatus = mRemoteComp->queue(workBundle);
+        Return<Status> transStatus = mSink->queue(workBundle);
         if (!transStatus.isOk()) {
-            ALOGD("compQueue -- transaction failed.");
+            LOG(ERROR) << "queueToSink -- transaction failed.";
             return C2_CORRUPTED;
         }
         c2_status_t status =
                 static_cast<c2_status_t>(static_cast<Status>(transStatus));
         if (status != C2_OK) {
-            ALOGV("compQueue -- call failed: %s.", asString(status));
+            LOG(DEBUG) << "queueToSink -- call failed: "
+                         << asString(status);
         }
         return status;
     }
 
-    wp<GraphicBufferSource> mSource;
-    std::weak_ptr<C2Component> mComp;
-    sp<IComponent> mRemoteComp;
-    std::string mCompName;
+    sp<GraphicBufferSource> mSource;
+    std::shared_ptr<C2Component> mLocalComp;
+    sp<IInputSink> mSink;
+    sp<IConfigurable> mSinkConfigurable;
+    std::string mSinkName;
 
     // Needed for ComponentWrapper implementation
     std::mutex mAllocatorMutex;
     std::shared_ptr<C2Allocator> mAllocator;
     std::atomic_uint64_t mFrameIndex;
+
 };
 
 InputSurfaceConnection::InputSurfaceConnection(
         const sp<GraphicBufferSource>& source,
-        const std::shared_ptr<C2Component>& comp) :
-    mSource(source),
-    mImpl(new Impl(source, comp)) {
+        const std::shared_ptr<C2Component>& comp,
+        const sp<ComponentStore>& store)
+      : mImpl{new Impl(source, comp)},
+        mConfigurable{new CachedConfigurable(
+            std::make_unique<Impl::ConfigurableIntf>(mImpl))} {
+    mConfigurable->init(store.get());
 }
 
 InputSurfaceConnection::InputSurfaceConnection(
         const sp<GraphicBufferSource>& source,
-        const sp<IComponent>& comp) :
-    mSource(source),
-    mImpl(new Impl(source, comp)) {
-}
-
-InputSurfaceConnection::~InputSurfaceConnection() {
-    if (mSource) {
-        (void)mSource->stop();
-        (void)mSource->release();
-        mSource.clear();
-    }
-    mImpl.clear();
-}
-
-bool InputSurfaceConnection::init() {
-    mMutex.lock();
-    sp<Impl> impl = mImpl;
-    mMutex.unlock();
-
-    if (!impl) {
-        return false;
-    }
-    return impl->init();
+        const sp<IInputSink>& sink,
+        const sp<ComponentStore>& store)
+      : mImpl{new Impl(source, sink)},
+        mConfigurable{new CachedConfigurable(
+            std::make_unique<Impl::ConfigurableIntf>(mImpl))} {
+    mConfigurable->init(store.get());
 }
 
 Return<Status> InputSurfaceConnection::disconnect() {
-    ALOGV("disconnect");
-    mMutex.lock();
-    if (mSource) {
-        (void)mSource->stop();
-        (void)mSource->release();
-        mSource.clear();
-    }
-    mImpl.clear();
-    mMutex.unlock();
-    ALOGV("disconnected");
+    std::lock_guard<std::mutex> lock(mImplMutex);
+    mImpl = nullptr;
     return Status::OK;
 }
 
+InputSurfaceConnection::~InputSurfaceConnection() {
+    mImpl = nullptr;
+}
+
+bool InputSurfaceConnection::init() {
+    std::lock_guard<std::mutex> lock(mImplMutex);
+    return mImpl->init();
+}
+
+Return<sp<IConfigurable>> InputSurfaceConnection::getConfigurable() {
+    return mConfigurable;
+}
+
+// Configurable interface for InputSurfaceConnection::Impl
+c2_status_t InputSurfaceConnection::Impl::ConfigurableIntf::config(
+        const std::vector<C2Param*> &params,
+        c2_blocking_t mayBlock,
+        std::vector<std::unique_ptr<C2SettingResult>> *const failures) {
+    // TODO: implement
+    (void)params;
+    (void)mayBlock;
+    (void)failures;
+    return C2_OK;
+}
+
+c2_status_t InputSurfaceConnection::Impl::ConfigurableIntf::query(
+        const std::vector<C2Param::Index> &indices,
+        c2_blocking_t mayBlock,
+        std::vector<std::unique_ptr<C2Param>> *const params) const {
+    // TODO: implement
+    (void)indices;
+    (void)mayBlock;
+    (void)params;
+    return C2_OK;
+}
+
+c2_status_t InputSurfaceConnection::Impl::ConfigurableIntf::querySupportedParams(
+        std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const {
+    // TODO: implement
+    (void)params;
+    return C2_OK;
+}
+
+c2_status_t InputSurfaceConnection::Impl::ConfigurableIntf::querySupportedValues(
+        std::vector<C2FieldSupportedValuesQuery> &fields,
+        c2_blocking_t mayBlock) const {
+    // TODO: implement
+    (void)fields;
+    (void)mayBlock;
+    return C2_OK;
+}
+
 }  // namespace utils
 }  // namespace V1_0
 }  // namespace c2
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Component.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Component.h
index 0908226..4ac95c5 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Component.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Component.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -17,13 +17,15 @@
 #ifndef CODEC2_HIDL_V1_0_UTILS_COMPONENT_H
 #define CODEC2_HIDL_V1_0_UTILS_COMPONENT_H
 
+#include <codec2/hidl/1.0/ComponentInterface.h>
 #include <codec2/hidl/1.0/Configurable.h>
 #include <codec2/hidl/1.0/types.h>
 
 #include <android/hardware/media/bufferpool/2.0/IClientManager.h>
+#include <android/hardware/media/c2/1.0/IComponent.h>
+#include <android/hardware/media/c2/1.0/IComponentInterface.h>
 #include <android/hardware/media/c2/1.0/IComponentListener.h>
 #include <android/hardware/media/c2/1.0/IComponentStore.h>
-#include <android/hardware/media/c2/1.0/IComponent.h>
 #include <hidl/Status.h>
 #include <hwbinder/IBinder.h>
 
@@ -31,9 +33,9 @@
 #include <C2Buffer.h>
 #include <C2.h>
 
-#include <list>
 #include <map>
 #include <memory>
+#include <mutex>
 
 namespace android {
 namespace hardware {
@@ -54,19 +56,8 @@
 
 struct ComponentStore;
 
-struct ComponentInterface : public Configurable<IComponentInterface> {
-    ComponentInterface(
-            const std::shared_ptr<C2ComponentInterface>& interface,
-            const sp<ComponentStore>& store);
-    c2_status_t status() const;
-
-protected:
-    c2_status_t mInit;
-    std::shared_ptr<C2ComponentInterface> mInterface;
-    sp<ComponentStore> mStore;
-};
-
-struct Component : public Configurable<IComponent> {
+struct Component : public IComponent,
+                   public std::enable_shared_from_this<Component> {
     Component(
             const std::shared_ptr<C2Component>&,
             const sp<IComponentListener>& listener,
@@ -85,10 +76,14 @@
     virtual Return<Status> setOutputSurface(
             uint64_t blockPoolId,
             const sp<HGraphicBufferProducer>& surface) override;
-    virtual Return<Status> connectToOmxInputSurface(
+    virtual Return<void> connectToInputSurface(
+            const sp<IInputSurface>& inputSurface,
+            connectToInputSurface_cb _hidl_cb) override;
+    virtual Return<void> connectToOmxInputSurface(
             const sp<HGraphicBufferProducer>& producer,
             const sp<::android::hardware::media::omx::V1_0::
-            IGraphicBufferSource>& source) override;
+            IGraphicBufferSource>& source,
+            connectToOmxInputSurface_cb _hidl_cb) override;
     virtual Return<Status> disconnectFromInputSurface() override;
     virtual Return<void> createBlockPool(
             uint32_t allocatorId,
@@ -98,63 +93,34 @@
     virtual Return<Status> stop() override;
     virtual Return<Status> reset() override;
     virtual Return<Status> release() override;
+    virtual Return<sp<IComponentInterface>> getInterface() override;
+
+    // Returns a C2Component associated to the given sink if the sink is indeed
+    // a local component. Returns nullptr otherwise.
+    //
+    // This function is used by InputSurface::connect().
+    static std::shared_ptr<C2Component> findLocalComponent(
+            const sp<IInputSink>& sink);
 
 protected:
     c2_status_t mInit;
     std::shared_ptr<C2Component> mComponent;
-    std::shared_ptr<C2ComponentInterface> mInterface;
+    sp<ComponentInterface> mInterface;
     sp<IComponentListener> mListener;
     sp<ComponentStore> mStore;
     ::android::hardware::media::c2::V1_0::utils::DefaultBufferPoolSender
             mBufferPoolSender;
 
+    struct Sink;
+    std::mutex mSinkMutex;
+    sp<Sink> mSink;
+
     std::mutex mBlockPoolsMutex;
     // This map keeps C2BlockPool objects that are created by createBlockPool()
     // alive. These C2BlockPool objects can be deleted by calling
     // destroyBlockPool(), reset() or release(), or by destroying the component.
     std::map<uint64_t, std::shared_ptr<C2BlockPool>> mBlockPools;
 
-    // This struct is a comparable wrapper for IComponent.
-    //
-    // An IComponent object is either local or remote. If it is local, we can
-    // use the underlying pointer as a key. If it is remote, we have to use the
-    // underlying pointer of the associated binder object as a key.
-    //
-    // See interfacesEqual() for more detail.
-    struct InterfaceKey {
-        // An InterfaceKey is constructed from IComponent.
-        InterfaceKey(const sp<IComponent>& component);
-        // operator< is defined here to control the default definition of
-        // std::less<InterfaceKey>, which will be used in type Roster defined
-        // below.
-        bool operator<(const InterfaceKey& other) const {
-            return isRemote ?
-                    (other.isRemote ?
-                        // remote & remote
-                        std::less<IBinder*>()(
-                            remote.unsafe_get(),
-                            other.remote.unsafe_get()) :
-                        // remote & local
-                        false) :
-                    (other.isRemote ?
-                        // local & remote
-                        true :
-                        // local & local
-                        std::less<IComponent*>()(
-                            local.unsafe_get(),
-                            other.local.unsafe_get()));
-        }
-    private:
-        bool isRemote;
-        wp<IBinder> remote;
-        wp<IComponent> local;
-    };
-
-    typedef std::map<InterfaceKey, std::weak_ptr<C2Component>> Roster;
-    typedef Roster::const_iterator LocalId;
-    LocalId mLocalId;
-    void setLocalId(const LocalId& localId);
-
     void initListener(const sp<Component>& self);
 
     virtual ~Component() override;
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentInterface.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentInterface.h
new file mode 100644
index 0000000..a5d235e
--- /dev/null
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentInterface.h
@@ -0,0 +1,66 @@
+/*
+ * 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 CODEC2_HIDL_V1_0_UTILS_COMPONENT_INTERFACE_H
+#define CODEC2_HIDL_V1_0_UTILS_COMPONENT_INTERFACE_H
+
+#include <codec2/hidl/1.0/Configurable.h>
+#include <codec2/hidl/1.0/types.h>
+
+#include <android/hardware/media/c2/1.0/IComponentInterface.h>
+#include <hidl/Status.h>
+
+#include <C2Component.h>
+#include <C2Buffer.h>
+#include <C2.h>
+
+#include <memory>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct ComponentStore;
+
+struct ComponentInterface : public IComponentInterface {
+    ComponentInterface(
+            const std::shared_ptr<C2ComponentInterface>& interface,
+            ComponentStore* store);
+    c2_status_t status() const;
+    virtual Return<sp<IConfigurable>> getConfigurable() override;
+
+protected:
+    std::shared_ptr<C2ComponentInterface> mInterface;
+    sp<CachedConfigurable> mConfigurable;
+    c2_status_t mInit;
+};
+
+
+}  // namespace utils
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // CODEC2_HIDL_V1_0_UTILS_COMPONENT_INTERFACE_H
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h
index 41e1416..be80c62 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -18,15 +18,18 @@
 #define CODEC2_HIDL_V1_0_UTILS_COMPONENTSTORE_H
 
 #include <codec2/hidl/1.0/Component.h>
+#include <codec2/hidl/1.0/ComponentInterface.h>
 #include <codec2/hidl/1.0/Configurable.h>
-#include <android/hardware/media/c2/1.0/IComponentStore.h>
+
 #include <android/hardware/media/bufferpool/2.0/IClientManager.h>
+#include <android/hardware/media/c2/1.0/IComponentStore.h>
 #include <hidl/Status.h>
 
 #include <C2Component.h>
 #include <C2Param.h>
 #include <C2.h>
 
+#include <chrono>
 #include <map>
 #include <memory>
 #include <mutex>
@@ -42,53 +45,61 @@
 
 using ::android::hardware::media::bufferpool::V2_0::IClientManager;
 
-using ::android::hardware::hidl_array;
 using ::android::hardware::hidl_handle;
-using ::android::hardware::hidl_memory;
 using ::android::hardware::hidl_string;
 using ::android::hardware::hidl_vec;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
 using ::android::sp;
-using ::android::wp;
 
-struct ComponentStore : public Configurable<IComponentStore> {
+struct ComponentStore : public IComponentStore {
     ComponentStore(const std::shared_ptr<C2ComponentStore>& store);
     virtual ~ComponentStore() = default;
 
-    c2_status_t status() const {
-        return mInit;
-    }
+    /**
+     * Returns the status of the construction of this object.
+     */
+    c2_status_t status() const;
 
+    /**
+     * This function is called by CachedConfigurable::init() to validate
+     * supported parameters.
+     */
     c2_status_t validateSupportedParams(
             const std::vector<std::shared_ptr<C2ParamDescriptor>>& params);
 
-    // Methods from ::android::hardware::media::c2::V1_0::IComponentStore
-    Return<void> createComponent(
+    // Methods from ::android::hardware::media::c2::V1_0::IComponentStore.
+    virtual Return<void> createComponent(
             const hidl_string& name,
             const sp<IComponentListener>& listener,
             const sp<IClientManager>& pool,
             createComponent_cb _hidl_cb) override;
-    Return<void> createInterface(
+    virtual Return<void> createInterface(
             const hidl_string& name,
             createInterface_cb _hidl_cb) override;
-    Return<void> listComponents(listComponents_cb _hidl_cb) override;
-    Return<sp<IInputSurface>> createInputSurface() override;
-    Return<void> getStructDescriptors(
+    virtual Return<void> listComponents(listComponents_cb _hidl_cb) override;
+    virtual Return<void> createInputSurface(
+            createInputSurface_cb _hidl_cb) override;
+    virtual Return<void> getStructDescriptors(
             const hidl_vec<uint32_t>& indices,
             getStructDescriptors_cb _hidl_cb) override;
-    Return<sp<IClientManager>> getPoolClientManager() override;
-    Return<Status> copyBuffer(
+    virtual Return<sp<IClientManager>> getPoolClientManager() override;
+    virtual Return<Status> copyBuffer(
             const Buffer& src,
             const Buffer& dst) override;
+    virtual Return<sp<IConfigurable>> getConfigurable() override;
 
-    // Debug dump
-    Return<void> debug(
+    /**
+     * Dumps information when lshal is called.
+     */
+    virtual Return<void> debug(
             const hidl_handle& handle,
             const hidl_vec<hidl_string>& args) override;
 
 protected:
-    // does bookkeeping for an interface that has been loaded
+    sp<CachedConfigurable> mConfigurable;
+
+    // Does bookkeeping for an interface that has been loaded.
     void onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf);
 
     c2_status_t mInit;
@@ -100,18 +111,33 @@
     std::set<C2String> mLoadedInterfaces;
     mutable std::mutex mStructDescriptorsMutex;
 
-    // Component lifetime management
-    Component::Roster mComponentRoster;
+    // ComponentStore keeps track of live Components.
+
+    struct ComponentStatus {
+        std::shared_ptr<C2Component> c2Component;
+        std::chrono::system_clock::time_point birthTime;
+    };
+
     mutable std::mutex mComponentRosterMutex;
-    void reportComponentDeath(const Component::LocalId& componentLocalId);
+    std::map<Component*, ComponentStatus> mComponentRoster;
+
+    // Called whenever Component is created.
+    void reportComponentBirth(Component* component);
+    // Called only from the destructor of Component.
+    void reportComponentDeath(Component* component);
 
     friend Component;
 
-    // C2Component lookup
-    std::shared_ptr<C2Component> findC2Component(
-            const sp<IComponent>& component) const;
+    // Helper functions for dumping.
 
-    friend struct InputSurface;
+    std::ostream& dump(
+            std::ostream& out,
+            const std::shared_ptr<const C2Component::Traits>& comp);
+
+    std::ostream& dump(
+            std::ostream& out,
+            ComponentStatus& compStatus);
+
 };
 
 }  // namespace utils
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Configurable.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Configurable.h
index 2e33a6f..8095185 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Configurable.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Configurable.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -17,15 +17,13 @@
 #ifndef CODEC2_HIDL_V1_0_UTILS_CONFIGURABLE_H
 #define CODEC2_HIDL_V1_0_UTILS_CONFIGURABLE_H
 
-#include <codec2/hidl/1.0/ConfigurableC2Intf.h>
+#include <android/hardware/media/c2/1.0/IConfigurable.h>
+#include <hidl/Status.h>
 
 #include <C2Component.h>
 #include <C2Param.h>
 #include <C2.h>
 
-#include <android/hardware/media/c2/1.0/IConfigurable.h>
-#include <hidl/Status.h>
-
 #include <memory>
 
 namespace android {
@@ -35,9 +33,6 @@
 namespace V1_0 {
 namespace utils {
 
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
 using ::android::hardware::hidl_vec;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
@@ -46,12 +41,52 @@
 struct ComponentStore;
 
 /**
+ * Codec2 objects of different types may have different querying and configuring
+ * functions, but across the Treble boundary, they share the same HIDL
+ * interface, IConfigurable.
+ *
+ * ConfigurableC2Intf is an abstract class that a Codec2 object can implement to
+ * easily expose an IConfigurable instance. See CachedConfigurable below.
+ */
+struct ConfigurableC2Intf {
+    C2String getName() const { return mName; }
+    uint32_t getId() const { return mId; }
+    /** C2ComponentInterface::query_vb sans stack params */
+    virtual c2_status_t query(
+            const std::vector<C2Param::Index> &indices,
+            c2_blocking_t mayBlock,
+            std::vector<std::unique_ptr<C2Param>>* const params) const = 0;
+    /** C2ComponentInterface::config_vb */
+    virtual c2_status_t config(
+            const std::vector<C2Param*> &params,
+            c2_blocking_t mayBlock,
+            std::vector<std::unique_ptr<C2SettingResult>>* const failures) = 0;
+    /** C2ComponentInterface::querySupportedParams_nb */
+    virtual c2_status_t querySupportedParams(
+            std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const = 0;
+    /** C2ComponentInterface::querySupportedParams_nb */
+    virtual c2_status_t querySupportedValues(
+            std::vector<C2FieldSupportedValuesQuery>& fields, c2_blocking_t mayBlock) const = 0;
+
+    virtual ~ConfigurableC2Intf() = default;
+
+    ConfigurableC2Intf(const C2String& name, uint32_t id)
+          : mName{name}, mId{id} {}
+
+protected:
+    C2String mName; /* cached component name */
+    uint32_t mId;
+};
+
+/**
  * Implementation of the IConfigurable interface that supports caching of
  * supported parameters from a supplied ComponentStore.
  *
- * This is mainly the same for all of the configurable C2 interfaces though
- * there are slight differences in the blocking behavior. This is handled in the
- * ConfigurableC2Intf implementations.
+ * CachedConfigurable essentially converts a ConfigurableC2Intf into HIDL's
+ * IConfigurable. A Codec2 object generally implements ConfigurableC2Intf and
+ * passes the implementation to the constructor of CachedConfigurable.
+ *
+ * Note that caching happens
  */
 struct CachedConfigurable : public IConfigurable {
     CachedConfigurable(std::unique_ptr<ConfigurableC2Intf>&& intf);
@@ -60,6 +95,8 @@
 
     // Methods from ::android::hardware::media::c2::V1_0::IConfigurable
 
+    virtual Return<uint32_t> getId() override;
+
     virtual Return<void> getName(getName_cb _hidl_cb) override;
 
     virtual Return<void> query(
@@ -90,63 +127,6 @@
     std::vector<std::shared_ptr<C2ParamDescriptor>> mSupportedParams;
 };
 
-/**
- * Template that implements the `IConfigurable` interface for an inherited
- * interface. Classes that implement a child interface `I` of `IConfigurable`
- * can derive from `Configurable<I>`.
- */
-template <typename I>
-struct Configurable : public I {
-    Configurable(const sp<CachedConfigurable>& intf): mIntf(intf) {
-    }
-
-    c2_status_t init(ComponentStore* store) {
-        return mIntf->init(store);
-    }
-
-    // Methods from ::android::hardware::media::c2::V1_0::IConfigurable
-
-    using getName_cb = typename I::getName_cb;
-    virtual Return<void> getName(getName_cb _hidl_cb) override {
-        return mIntf->getName(_hidl_cb);
-    }
-
-    using query_cb = typename I::query_cb;
-    virtual Return<void> query(
-            const hidl_vec<uint32_t>& indices,
-            bool mayBlock,
-            query_cb _hidl_cb) override {
-        return mIntf->query(indices, mayBlock, _hidl_cb);
-    }
-
-    using config_cb = typename I::config_cb;
-    virtual Return<void> config(
-            const hidl_vec<uint8_t>& inParams,
-            bool mayBlock,
-            config_cb _hidl_cb) override {
-        return mIntf->config(inParams, mayBlock, _hidl_cb);
-    }
-
-    using querySupportedParams_cb = typename I::querySupportedParams_cb;
-    virtual Return<void> querySupportedParams(
-            uint32_t start,
-            uint32_t count,
-            querySupportedParams_cb _hidl_cb) override {
-        return mIntf->querySupportedParams(start, count, _hidl_cb);
-    }
-
-    using querySupportedValues_cb = typename I::querySupportedValues_cb;
-    virtual Return<void> querySupportedValues(
-            const hidl_vec<FieldSupportedValuesQuery>& inFields,
-            bool mayBlock,
-            querySupportedValues_cb _hidl_cb) override {
-        return mIntf->querySupportedValues(inFields, mayBlock, _hidl_cb);
-    }
-
-protected:
-    sp<CachedConfigurable> mIntf;
-};
-
 }  // namespace utils
 }  // namespace V1_0
 }  // namespace c2
@@ -155,3 +135,4 @@
 }  // namespace android
 
 #endif  // CODEC2_HIDL_V1_0_UTILS_CONFIGURABLE_H
+
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ConfigurableC2Intf.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ConfigurableC2Intf.h
deleted file mode 100644
index b8801bb..0000000
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ConfigurableC2Intf.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * 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 CODEC2_HIDL_V1_0_UTILS_CONFIGURABLEC2INTF_H
-#define CODEC2_HIDL_V1_0_UTILS_CONFIGURABLEC2INTF_H
-
-#include <C2Work.h>
-#include <C2Component.h>
-#include <C2Param.h>
-#include <C2.h>
-
-#include <hidl/HidlSupport.h>
-#include <utils/StrongPointer.h>
-#include <vector>
-#include <memory>
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace c2 {
-namespace V1_0 {
-namespace utils {
-
-using ::android::sp;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-
-/**
- * Common Codec 2.0 interface wrapper.
- */
-struct ConfigurableC2Intf {
-    C2String getName() const { return mName; }
-    /** C2ComponentInterface::query_vb sans stack params */
-    virtual c2_status_t query(
-            const std::vector<C2Param::Index> &indices,
-            c2_blocking_t mayBlock,
-            std::vector<std::unique_ptr<C2Param>>* const params) const = 0;
-    /** C2ComponentInterface::config_vb */
-    virtual c2_status_t config(
-            const std::vector<C2Param*> &params,
-            c2_blocking_t mayBlock,
-            std::vector<std::unique_ptr<C2SettingResult>>* const failures) = 0;
-    /** C2ComponentInterface::querySupportedParams_nb */
-    virtual c2_status_t querySupportedParams(
-            std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const = 0;
-    /** C2ComponentInterface::querySupportedParams_nb */
-    virtual c2_status_t querySupportedValues(
-            std::vector<C2FieldSupportedValuesQuery>& fields, c2_blocking_t mayBlock) const = 0;
-
-    virtual ~ConfigurableC2Intf() = default;
-
-    ConfigurableC2Intf(const C2String& name) : mName(name) {}
-
-protected:
-    C2String mName; /* cache component name */
-};
-
-}  // namespace utils
-}  // namespace V1_0
-}  // namespace c2
-}  // namespace media
-}  // namespace hardware
-}  // namespace android
-
-#endif  // CODEC2_HIDL_V1_0_UTILS_CONFIGURABLEC2INTF_H
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputBufferManager.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputBufferManager.h
new file mode 100644
index 0000000..b6857d5
--- /dev/null
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputBufferManager.h
@@ -0,0 +1,294 @@
+/*
+ * 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 CODEC2_HIDL_V1_0_UTILS_INPUT_BUFFER_MANAGER_H
+#define CODEC2_HIDL_V1_0_UTILS_INPUT_BUFFER_MANAGER_H
+
+#include <android/hardware/media/c2/1.0/IComponentListener.h>
+#include <utils/Timers.h>
+
+#include <C2Buffer.h>
+#include <C2Work.h>
+
+#include <set>
+#include <map>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using namespace ::android;
+
+/**
+ * InputBufferManager
+ * ==================
+ *
+ * InputBufferManager presents a way to track and untrack input buffers in this
+ * (codec) process and send a notification to a listener, possibly in a
+ * different process, when a tracked buffer no longer has any references in this
+ * process.
+ *
+ * InputBufferManager holds a collection of records representing tracked buffers
+ * and their callback listeners. Conceptually, one record is a triple (listener,
+ * frameIndex, bufferIndex) where
+ *
+ * - (frameIndex, bufferIndex) is a pair of indices used to identify the buffer.
+ * - listener is of type IComponentListener. Its onInputBuffersReleased()
+ *   function will be called after the associated buffer dies. The argument of
+ *   onInputBuffersReleased() is a list of InputBuffer objects, each of which
+ *   has the following members:
+ *
+ *     uint64_t frameIndex
+ *     uint32_t arrayIndex
+ *
+ * When a tracked buffer associated to the triple (listener, frameIndex,
+ * bufferIndex) goes out of scope, listener->onInputBuffersReleased() will be
+ * called with an InputBuffer object whose members are set as follows:
+ *
+ *     inputBuffer.frameIndex = frameIndex
+ *     inputBuffer.arrayIndex = bufferIndex
+ *
+ * IPC Optimization
+ * ----------------
+ *
+ * Since onInputBuffersReleased() is an IPC call, InputBufferManager tries not
+ * to call it too often. Any two calls to the same listener are at least
+ * mNotificationIntervalNs nanoseconds apart, where mNotificationIntervalNs is
+ * configurable via calling setNotificationInterval(). The default value of
+ * mNotificationIntervalNs is kDefaultNotificationInternalNs.
+ *
+ * Public Member Functions
+ * -----------------------
+ *
+ * InputBufferManager is a singleton class. Its only instance is accessible via
+ * the following public functions:
+ *
+ * - registerFrameData(const sp<IComponentListener>& listener,
+ *                     const C2FrameData& input)
+ *
+ * - unregisterFrameData(const sp<IComponentListener>& listener,
+ *                       const C2FrameData& input)
+ *
+ * - unregisterFrameData(const sp<IComponentListener>& listener)
+ *
+ * - setNotificationInterval(nsecs_t notificationIntervalNs)
+ *
+ */
+
+struct InputBufferManager {
+
+    /**
+     * The default value for the time interval between 2 subsequent IPCs.
+     */
+    static constexpr nsecs_t kDefaultNotificationIntervalNs = 1000000; /* 1ms */
+
+    /**
+     * Track all buffers in a C2FrameData object.
+     *
+     * input (C2FrameData) has the following two members that are of interest:
+     *
+     *   C2WorkOrdinal                ordinal
+     *   vector<shared_ptr<C2Buffer>> buffers
+     *
+     * Calling registerFrameData(listener, input) will register multiple
+     * triples (listener, frameIndex, bufferIndex) where frameIndex is equal to
+     * input.ordinal.frameIndex and bufferIndex runs through the indices of
+     * input.buffers such that input.buffers[bufferIndex] is not null.
+     *
+     * This should be called from queue().
+     *
+     * \param listener Listener of death notifications.
+     * \param input Input frame data whose input buffers are to be tracked.
+     */
+    static void registerFrameData(
+            const sp<IComponentListener>& listener,
+            const C2FrameData& input);
+
+    /**
+     * Untrack all buffers in a C2FrameData object.
+     *
+     * Calling unregisterFrameData(listener, input) will unregister and remove
+     * pending notifications for all triples (l, fi, bufferIndex) such that
+     * l = listener and fi = input.ordinal.frameIndex.
+     *
+     * This should be called from onWorkDone() and flush().
+     *
+     * \param listener Previously registered listener.
+     * \param input Previously registered frame data.
+     */
+    static void unregisterFrameData(
+            const wp<IComponentListener>& listener,
+            const C2FrameData& input);
+
+    /**
+     * Untrack all buffers associated to a given listener.
+     *
+     * Calling unregisterFrameData(listener) will unregister and remove
+     * pending notifications for all triples (l, frameIndex, bufferIndex) such
+     * that l = listener.
+     *
+     * This should be called when the component cleans up all input buffers,
+     * i.e., when reset(), release(), stop() or ~Component() is called.
+     *
+     * \param listener Previously registered listener.
+     */
+    static void unregisterFrameData(
+            const wp<IComponentListener>& listener);
+
+    /**
+     * Set the notification interval.
+     *
+     * \param notificationIntervalNs New notification interval, in nanoseconds.
+     */
+    static void setNotificationInterval(nsecs_t notificationIntervalNs);
+
+private:
+    void _registerFrameData(
+            const sp<IComponentListener>& listener,
+            const C2FrameData& input);
+    void _unregisterFrameData(
+            const wp<IComponentListener>& listener,
+            const C2FrameData& input);
+    void _unregisterFrameData(
+            const wp<IComponentListener>& listener);
+    void _setNotificationInterval(nsecs_t notificationIntervalNs);
+
+    // The callback function tied to C2Buffer objects.
+    //
+    // Note: This function assumes that sInstance is the only instance of this
+    //       class.
+    static void onBufferDestroyed(const C2Buffer* buf, void* arg);
+    void _onBufferDestroyed(const C2Buffer* buf, void* arg);
+
+    // Persistent data to be passed as "arg" in onBufferDestroyed().
+    // This is essentially the triple (listener, frameIndex, bufferIndex) plus a
+    // weak pointer to the C2Buffer object.
+    //
+    // Note that the "key" is bufferIndex according to operator<(). This is
+    // designed to work with TrackedBuffersMap defined below.
+    struct TrackedBuffer {
+        wp<IComponentListener> listener;
+        uint64_t frameIndex;
+        size_t bufferIndex;
+        std::weak_ptr<C2Buffer> buffer;
+        TrackedBuffer(const wp<IComponentListener>& listener,
+                      uint64_t frameIndex,
+                      size_t bufferIndex,
+                      const std::shared_ptr<C2Buffer>& buffer)
+              : listener(listener),
+                frameIndex(frameIndex),
+                bufferIndex(bufferIndex),
+                buffer(buffer) {}
+        TrackedBuffer(const TrackedBuffer&) = default;
+        bool operator<(const TrackedBuffer& other) const {
+            return bufferIndex < other.bufferIndex;
+        }
+    };
+
+    // Map: listener -> frameIndex -> set<TrackedBuffer>.
+    // Essentially, this is used to store triples (listener, frameIndex,
+    // bufferIndex) that's searchable by listener and (listener, frameIndex).
+    // However, the value of the innermost map is TrackedBuffer, which also
+    // contains an extra copy of listener and frameIndex. This is needed
+    // because onBufferDestroyed() needs to know listener and frameIndex too.
+    typedef std::map<wp<IComponentListener>,
+                     std::map<uint64_t,
+                              std::set<TrackedBuffer>>> TrackedBuffersMap;
+
+    // Storage for pending (unsent) death notifications for one listener.
+    // Each pair in member named "indices" are (frameIndex, bufferIndex) from
+    // the (listener, frameIndex, bufferIndex) triple.
+    struct DeathNotifications {
+
+        // The number of pending notifications for this listener.
+        // count may be 0, in which case the DeathNotifications object will
+        // remain valid for only a small period (specified
+        // nanoseconds).
+        size_t count;
+
+        // The timestamp of the most recent callback on this listener. This is
+        // used to guarantee that callbacks do not occur too frequently, and
+        // also to trigger expiration of a DeathNotifications object that has
+        // count = 0.
+        nsecs_t lastSentNs;
+
+        // Map: frameIndex -> vector of bufferIndices
+        // This is essentially a collection of (framdeIndex, bufferIndex).
+        std::map<uint64_t, std::vector<size_t>> indices;
+
+        DeathNotifications(
+                nsecs_t notificationIntervalNs = kDefaultNotificationIntervalNs)
+              : count(0),
+                lastSentNs(systemTime() - notificationIntervalNs),
+                indices() {}
+    };
+
+    // The minimum time period between IPC calls to notify the client about the
+    // destruction of input buffers.
+    std::atomic<nsecs_t> mNotificationIntervalNs{kDefaultNotificationIntervalNs};
+
+    // Mutex for the management of all input buffers.
+    std::mutex mMutex;
+
+    // Tracked input buffers.
+    TrackedBuffersMap mTrackedBuffersMap;
+
+    // Death notifications to be sent.
+    //
+    // A DeathNotifications object is associated to each listener. An entry in
+    // this map will be removed if its associated DeathNotifications has count =
+    // 0 and lastSentNs < systemTime() - mNotificationIntervalNs.
+    std::map<wp<IComponentListener>, DeathNotifications> mDeathNotifications;
+
+    // Condition variable signaled when an entry is added to mDeathNotifications.
+    std::condition_variable mOnBufferDestroyed;
+
+    // Notify the clients about buffer destructions.
+    // Return false if all destructions have been notified.
+    // Return true and set timeToRetry to the duration to wait for before
+    // retrying if some destructions have not been notified.
+    bool processNotifications(nsecs_t* timeToRetryNs);
+
+    // Main function for the input buffer manager thread.
+    void main();
+
+    // The thread that manages notifications.
+    //
+    // Note: This variable is declared last so its initialization will happen
+    // after all other member variables have been initialized.
+    std::thread mMainThread;
+
+    // Private constructor.
+    InputBufferManager();
+
+    // The only instance of this class.
+    static InputBufferManager& getInstance();
+
+};
+
+}  // namespace utils
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // CODEC2_HIDL_V1_0_UTILS_INPUT_BUFFER_MANAGER_H
+
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurface.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurface.h
index cef258e..2682c13 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurface.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurface.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -19,21 +19,14 @@
 
 #include <codec2/hidl/1.0/ComponentStore.h>
 
-#include <android/hardware/media/c2/1.0/IInputSurface.h>
-#include <android/hardware/media/c2/1.0/IComponent.h>
-
 #include <android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h>
-#include <android/hardware/graphics/bufferqueue/1.0/IProducerListener.h>
-#include <android/hardware/graphics/common/1.0/types.h>
-#include <android/hardware/media/1.0/types.h>
-
+#include <android/hardware/media/c2/1.0/IInputSink.h>
+#include <android/hardware/media/c2/1.0/IInputSurface.h>
 #include <gui/IGraphicBufferProducer.h>
+#include <hidl/Status.h>
 #include <media/stagefright/bqhelper/GraphicBufferSource.h>
 
-#include <hidl/HidlSupport.h>
-#include <hidl/Status.h>
-
-class C2ReflectorHelper;
+#include <util/C2InterfaceHelper.h>
 
 namespace android {
 namespace hardware {
@@ -49,133 +42,31 @@
 using ::android::hardware::Void;
 using ::android::sp;
 
-using ::android::hardware::graphics::common::V1_0::PixelFormat;
-using ::android::hardware::media::V1_0::AnwBuffer;
-
 struct InputSurface : public IInputSurface {
 
-    typedef ::android::hidl::base::V1_0::IBase IBase;
-
-    typedef ::android::hardware::graphics::bufferqueue::V1_0::
-            IProducerListener HProducerListener;
-
-    typedef ::android::
-            IGraphicBufferProducer BGraphicBufferProducer;
-
     typedef ::android::hardware::graphics::bufferqueue::V1_0::
             IGraphicBufferProducer HGraphicBufferProducer;
 
     typedef ::android::
             GraphicBufferSource GraphicBufferSource;
 
-// Type disambiguation
-
-    typedef ::android::hardware::media::c2::V1_0::Status Status;
-
-// New methods from IInputSurface
-
-    virtual Return<void> connectToComponent(
-            const sp<IComponent>& component,
-            connectToComponent_cb _hidl_cb) override;
+    virtual Return<sp<HGraphicBufferProducer>> getGraphicBufferProducer() override;
 
     virtual Return<sp<IConfigurable>> getConfigurable() override;
 
-// Methods derived from IGraphicBufferProducer
-
-    virtual Return<void> requestBuffer(
-            int32_t slot,
-            requestBuffer_cb _hidl_cb) override;
-
-    virtual Return<int32_t> setMaxDequeuedBufferCount(
-            int32_t maxDequeuedBuffers) override;
-
-    virtual Return<int32_t> setAsyncMode(
-            bool async) override;
-
-    virtual Return<void> dequeueBuffer(
-            uint32_t width,
-            uint32_t height,
-            PixelFormat format,
-            uint32_t usage,
-            bool getFrameTimestamps,
-            dequeueBuffer_cb _hidl_cb) override;
-
-    virtual Return<int32_t> detachBuffer(
-            int32_t slot) override;
-
-    virtual Return<void> detachNextBuffer(
-            detachNextBuffer_cb _hidl_cb) override;
-
-    virtual Return<void> attachBuffer(
-            const AnwBuffer& buffer,
-            attachBuffer_cb _hidl_cb) override;
-
-    virtual Return<void> queueBuffer(
-            int32_t slot,
-            const QueueBufferInput& input,
-            queueBuffer_cb _hidl_cb) override;
-
-    virtual Return<int32_t> cancelBuffer(
-            int32_t slot,
-            const hidl_handle& fence) override;
-
-    virtual Return<void> query(
-            int32_t what,
-            query_cb _hidl_cb) override;
-
     virtual Return<void> connect(
-            const sp<HProducerListener>& listener,
-            int32_t api,
-            bool producerControlledByApp,
+            const sp<IInputSink>& sink,
             connect_cb _hidl_cb) override;
 
-    virtual Return<int32_t> disconnect(
-            int32_t api,
-            DisconnectMode mode) override;
-
-    virtual Return<int32_t> setSidebandStream(
-            const hidl_handle& stream) override;
-
-    virtual Return<void> allocateBuffers(
-            uint32_t width,
-            uint32_t height,
-            PixelFormat format,
-            uint32_t usage) override;
-
-    virtual Return<int32_t> allowAllocation(
-            bool allow) override;
-
-    virtual Return<int32_t> setGenerationNumber(
-            uint32_t generationNumber) override;
-
-    virtual Return<void> getConsumerName(
-            getConsumerName_cb _hidl_cb) override;
-
-    virtual Return<int32_t> setSharedBufferMode(
-            bool sharedBufferMode) override;
-
-    virtual Return<int32_t> setAutoRefresh(
-            bool autoRefresh) override;
-
-    virtual Return<int32_t> setDequeueTimeout(
-            int64_t timeoutNs) override;
-
-    virtual Return<void> getLastQueuedBuffer(
-            getLastQueuedBuffer_cb _hidl_cb) override;
-
-    virtual Return<void> getFrameTimestamps(
-            getFrameTimestamps_cb _hidl_cb) override;
-
-    virtual Return<void> getUniqueId(
-            getUniqueId_cb _hidl_cb) override;
-
-    class ConfigurableImpl;
-
 protected:
+
+    class Interface;
+    class ConfigurableIntf;
+
     sp<ComponentStore> mStore;
-    sp<HGraphicBufferProducer> mBase;
+    sp<HGraphicBufferProducer> mProducer;
     sp<GraphicBufferSource> mSource;
-    std::shared_ptr<ConfigurableImpl> mHelper;
+    std::shared_ptr<Interface> mIntf;
     sp<CachedConfigurable> mConfigurable;
 
     InputSurface(
@@ -187,6 +78,7 @@
     virtual ~InputSurface() override = default;
 
     friend struct ComponentStore;
+
 };
 
 
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurfaceConnection.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurfaceConnection.h
index 904fa9e..758b6b2 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurfaceConnection.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurfaceConnection.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -18,8 +18,10 @@
 #define CODEC2_HIDL_V1_0_UTILS_INPUTSURFACECONNECTION_H
 
 #include <codec2/hidl/1.0/Component.h>
+#include <codec2/hidl/1.0/Configurable.h>
 
 #include <android/hardware/media/c2/1.0/IComponent.h>
+#include <android/hardware/media/c2/1.0/IConfigurable.h>
 #include <android/hardware/media/c2/1.0/IInputSurfaceConnection.h>
 
 #include <media/stagefright/bqhelper/GraphicBufferSource.h>
@@ -44,19 +46,28 @@
 using ::android::sp;
 using ::android::GraphicBufferSource;
 
+// An InputSurfaceConnection connects an InputSurface to a sink, which may be an
+// IInputSink or a local C2Component. This can be specified by choosing the
+// corresponding constructor. The reason for distinguishing these two cases is
+// that when an InputSurfaceConnection lives in the same process as the
+// component that processes the buffers, data parceling is not needed.
 struct InputSurfaceConnection : public IInputSurfaceConnection {
 
     virtual Return<Status> disconnect() override;
 
+    virtual Return<sp<IConfigurable>> getConfigurable() override;
+
 protected:
 
     InputSurfaceConnection(
             const sp<GraphicBufferSource>& source,
-            const std::shared_ptr<C2Component>& component);
+            const std::shared_ptr<C2Component>& comp,
+            const sp<ComponentStore>& store);
 
     InputSurfaceConnection(
             const sp<GraphicBufferSource>& source,
-            const sp<IComponent>& component);
+            const sp<IInputSink>& sink,
+            const sp<ComponentStore>& store);
 
     bool init();
 
@@ -68,9 +79,9 @@
 
     struct Impl;
 
-    std::mutex mMutex;
-    sp<GraphicBufferSource> mSource;
+    std::mutex mImplMutex;
     sp<Impl> mImpl;
+    sp<CachedConfigurable> mConfigurable;
 
     virtual ~InputSurfaceConnection() override;
 };
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/types.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/types.h
index d8a50b6..c38e674 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/types.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/types.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -17,8 +17,6 @@
 #ifndef CODEC2_HIDL_V1_0_UTILS_TYPES_H
 #define CODEC2_HIDL_V1_0_UTILS_TYPES_H
 
-#include <chrono>
-
 #include <bufferpool/ClientManager.h>
 #include <android/hardware/media/bufferpool/2.0/IClientManager.h>
 #include <android/hardware/media/bufferpool/2.0/types.h>
@@ -30,6 +28,9 @@
 #include <C2Param.h>
 #include <C2ParamDef.h>
 #include <C2Work.h>
+#include <util/C2Debug-base.h>
+
+#include <chrono>
 
 using namespace std::chrono_literals;
 
@@ -65,66 +66,74 @@
 };
 typedef C2GlobalParam<C2Info, C2Hidl_Rect, 1> C2Hidl_RectInfo;
 
+// Make asString() and operator<< work with Status as well as c2_status_t.
+C2_DECLARE_AS_STRING_AND_DEFINE_STREAM_OUT(Status);
+
+/**
+ * All objcpy() functions will return a boolean value indicating whether the
+ * conversion succeeds or not.
+ */
+
 // C2SettingResult -> SettingResult
-Status objcpy(
+bool objcpy(
         SettingResult* d,
         const C2SettingResult& s);
 
 // SettingResult -> std::unique_ptr<C2SettingResult>
-c2_status_t objcpy(
+bool objcpy(
         std::unique_ptr<C2SettingResult>* d,
         const SettingResult& s);
 
 // C2ParamDescriptor -> ParamDescriptor
-Status objcpy(
+bool objcpy(
         ParamDescriptor* d,
         const C2ParamDescriptor& s);
 
 // ParamDescriptor -> std::shared_ptr<C2ParamDescriptor>
-c2_status_t objcpy(
+bool objcpy(
         std::shared_ptr<C2ParamDescriptor>* d,
         const ParamDescriptor& s);
 
 // C2FieldSupportedValuesQuery -> FieldSupportedValuesQuery
-Status objcpy(
+bool objcpy(
         FieldSupportedValuesQuery* d,
         const C2FieldSupportedValuesQuery& s);
 
 // FieldSupportedValuesQuery -> C2FieldSupportedValuesQuery
-c2_status_t objcpy(
+bool objcpy(
         C2FieldSupportedValuesQuery* d,
         const FieldSupportedValuesQuery& s);
 
 // C2FieldSupportedValuesQuery -> FieldSupportedValuesQueryResult
-Status objcpy(
+bool objcpy(
         FieldSupportedValuesQueryResult* d,
         const C2FieldSupportedValuesQuery& s);
 
 // FieldSupportedValuesQuery, FieldSupportedValuesQueryResult -> C2FieldSupportedValuesQuery
-c2_status_t objcpy(
+bool objcpy(
         C2FieldSupportedValuesQuery* d,
         const FieldSupportedValuesQuery& sq,
         const FieldSupportedValuesQueryResult& sr);
 
 // C2Component::Traits -> ComponentTraits
-Status objcpy(
+bool objcpy(
         IComponentStore::ComponentTraits* d,
         const C2Component::Traits& s);
 
 // ComponentTraits -> C2Component::Traits, std::unique_ptr<std::vector<std::string>>
 // Note: The output d is only valid as long as aliasesBuffer remains alive.
-c2_status_t objcpy(
+bool objcpy(
         C2Component::Traits* d,
         std::unique_ptr<std::vector<std::string>>* aliasesBuffer,
         const IComponentStore::ComponentTraits& s);
 
 // C2StructDescriptor -> StructDescriptor
-Status objcpy(
+bool objcpy(
         StructDescriptor* d,
         const C2StructDescriptor& s);
 
 // StructDescriptor -> C2StructDescriptor
-c2_status_t objcpy(
+bool objcpy(
         std::unique_ptr<C2StructDescriptor>* d,
         const StructDescriptor& s);
 
@@ -208,68 +217,77 @@
 
 // std::list<std::unique_ptr<C2Work>> -> WorkBundle
 // Note: If bufferpool will be used, bpSender must not be null.
-Status objcpy(
+bool objcpy(
         WorkBundle* d,
         const std::list<std::unique_ptr<C2Work>>& s,
         BufferPoolSender* bpSender = nullptr);
 
 // WorkBundle -> std::list<std::unique_ptr<C2Work>>
-c2_status_t objcpy(
+bool objcpy(
         std::list<std::unique_ptr<C2Work>>* d,
         const WorkBundle& s);
 
 /**
- * Parses a params blob and returns C2Param pointers to its params.
+ * Parses a params blob and returns C2Param pointers to its params. The pointers
+ * point to locations inside the underlying buffer of \p blob. If \p blob is
+ * destroyed, the pointers become invalid.
+ *
  * \param[out] params target vector of C2Param pointers
  * \param[in] blob parameter blob to parse
- * \retval C2_OK if the full blob was parsed
- * \retval C2_BAD_VALUE otherwise
+ * \retval true if the full blob was parsed
+ * \retval false otherwise
  */
-c2_status_t parseParamsBlob(
+bool parseParamsBlob(
         std::vector<C2Param*> *params,
         const hidl_vec<uint8_t> &blob);
 
 /**
  * Concatenates a list of C2Params into a params blob.
+ *
  * \param[out] blob target blob
  * \param[in] params parameters to concatenate
- * \retval C2_OK if the blob was successfully created
- * \retval C2_BAD_VALUE if the blob was not successful (this only happens if the parameters were
- *         not const)
+ * \retval true if the blob was successfully created
+ * \retval false if the blob was not successful (this only happens if the
+ *         parameters were not const)
  */
-Status createParamsBlob(
+bool createParamsBlob(
         hidl_vec<uint8_t> *blob,
         const std::vector<C2Param*> &params);
-Status createParamsBlob(
+bool createParamsBlob(
         hidl_vec<uint8_t> *blob,
         const std::vector<std::unique_ptr<C2Param>> &params);
-Status createParamsBlob(
+bool createParamsBlob(
         hidl_vec<uint8_t> *blob,
         const std::vector<std::shared_ptr<const C2Info>> &params);
-Status createParamsBlob(
+bool createParamsBlob(
         hidl_vec<uint8_t> *blob,
         const std::vector<std::unique_ptr<C2Tuning>> &params);
 
 /**
  * Parses a params blob and create a vector of C2Params whose members are copies
  * of the params in the blob.
+ *
  * \param[out] params the resulting vector
  * \param[in] blob parameter blob to parse
- * \retval C2_OK if the full blob was parsed and params was constructed
- * \retval C2_BAD_VALUE otherwise
+ * \retval true if the full blob was parsed and params was constructed
+ * \retval false otherwise
  */
-c2_status_t copyParamsFromBlob(
+bool copyParamsFromBlob(
         std::vector<std::unique_ptr<C2Param>>* params,
         Params blob);
+bool copyParamsFromBlob(
+        std::vector<std::unique_ptr<C2Tuning>>* params,
+        Params blob);
 
 /**
- * Parses a params blob and applies updates to params
+ * Parses a params blob and applies updates to params.
+ *
  * \param[in,out] params params to be updated
  * \param[in] blob parameter blob containing updates
- * \retval C2_OK if the full blob was parsed and params was updated
- * \retval C2_BAD_VALUE otherwise
+ * \retval true if the full blob was parsed and params was updated
+ * \retval false otherwise
  */
-c2_status_t updateParamsFromBlob(
+bool updateParamsFromBlob(
         const std::vector<C2Param*>& params,
         const Params& blob);
 
diff --git a/media/codec2/hidl/1.0/utils/types.cpp b/media/codec2/hidl/1.0/utils/types.cpp
index a128a9d..caed839 100644
--- a/media/codec2/hidl/1.0/utils/types.cpp
+++ b/media/codec2/hidl/1.0/utils/types.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -16,11 +16,12 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "Codec2-types"
-#include <log/log.h>
+#include <android-base/logging.h>
 
 #include <codec2/hidl/1.0/types.h>
 
 #include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
+#include <media/stagefright/foundation/AUtils.h>
 
 #include <C2AllocatorIon.h>
 #include <C2AllocatorGralloc.h>
@@ -35,10 +36,9 @@
 
 #include <algorithm>
 #include <functional>
+#include <iomanip>
 #include <unordered_map>
 
-#include <media/stagefright/foundation/AUtils.h>
-
 namespace android {
 namespace hardware {
 namespace media {
@@ -57,8 +57,18 @@
         TransactionId;
 using ::android::TWGraphicBufferProducer;
 
+const char* asString(Status status, const char* def) {
+    return asString(static_cast<c2_status_t>(status), def);
+}
+
 namespace /* unnamed */ {
 
+template <typename EnumClass>
+typename std::underlying_type<EnumClass>::type underlying_value(
+        EnumClass x) {
+    return static_cast<typename std::underlying_type<EnumClass>::type>(x);
+}
+
 template <typename Common, typename DstVector, typename SrcVector>
 void copyVector(DstVector* d, const SrcVector& s) {
     static_assert(sizeof(Common) == sizeof(decltype((*d)[0])),
@@ -73,10 +83,11 @@
 }
 
 // C2ParamField -> ParamField
-void objcpy(ParamField *d, const C2ParamField &s) {
+bool objcpy(ParamField *d, const C2ParamField &s) {
     d->index = static_cast<ParamIndex>(_C2ParamInspector::GetIndex(s));
     d->fieldId.offset = static_cast<uint32_t>(_C2ParamInspector::GetOffset(s));
     d->fieldId.size = static_cast<uint32_t>(_C2ParamInspector::GetSize(s));
+    return true;
 }
 
 struct C2ParamFieldBuilder : public C2ParamField {
@@ -92,21 +103,23 @@
 };
 
 // C2WorkOrdinalStruct -> WorkOrdinal
-void objcpy(WorkOrdinal *d, const C2WorkOrdinalStruct &s) {
+bool objcpy(WorkOrdinal *d, const C2WorkOrdinalStruct &s) {
     d->frameIndex = static_cast<uint64_t>(s.frameIndex.peeku());
     d->timestampUs = static_cast<uint64_t>(s.timestamp.peeku());
     d->customOrdinal = static_cast<uint64_t>(s.customOrdinal.peeku());
+    return true;
 }
 
 // WorkOrdinal -> C2WorkOrdinalStruct
-void objcpy(C2WorkOrdinalStruct *d, const WorkOrdinal &s) {
+bool objcpy(C2WorkOrdinalStruct *d, const WorkOrdinal &s) {
     d->frameIndex = c2_cntr64_t(s.frameIndex);
     d->timestamp = c2_cntr64_t(s.timestampUs);
     d->customOrdinal = c2_cntr64_t(s.customOrdinal);
+    return true;
 }
 
 // C2FieldSupportedValues::range's type -> FieldSupportedValues::Range
-void objcpy(
+bool objcpy(
         FieldSupportedValues::Range* d,
         const decltype(C2FieldSupportedValues::range)& s) {
     d->min = static_cast<PrimitiveValue>(s.min.u64);
@@ -114,21 +127,24 @@
     d->step = static_cast<PrimitiveValue>(s.step.u64);
     d->num = static_cast<PrimitiveValue>(s.num.u64);
     d->denom = static_cast<PrimitiveValue>(s.denom.u64);
+    return true;
 }
 
 // C2FieldSupportedValues -> FieldSupportedValues
-Status objcpy(FieldSupportedValues *d, const C2FieldSupportedValues &s) {
-    d->typeOther = static_cast<int32_t>(s.type);
+bool objcpy(FieldSupportedValues *d, const C2FieldSupportedValues &s) {
     switch (s.type) {
     case C2FieldSupportedValues::EMPTY:
         d->type = FieldSupportedValues::Type::EMPTY;
         d->values.resize(0);
-        return Status::OK;
+        break;
     case C2FieldSupportedValues::RANGE:
         d->type = FieldSupportedValues::Type::RANGE;
-        objcpy(&d->range, s.range);
+        if (!objcpy(&d->range, s.range)) {
+            LOG(ERROR) << "Invalid C2FieldSupportedValues::range.";
+            return false;
+        }
         d->values.resize(0);
-        return Status::OK;
+        break;
     default:
         switch (s.type) {
         case C2FieldSupportedValues::VALUES:
@@ -138,18 +154,22 @@
             d->type = FieldSupportedValues::Type::FLAGS;
             break;
         default:
-            d->type = FieldSupportedValues::Type::OTHER;
-            // Copy all fields in this case
-            objcpy(&d->range, s.range);
+            LOG(DEBUG) << "Unrecognized C2FieldSupportedValues::type_t "
+                       << "with underlying value " << underlying_value(s.type)
+                       << ".";
+            d->type = static_cast<FieldSupportedValues::Type>(s.type);
+            if (!objcpy(&d->range, s.range)) {
+                LOG(ERROR) << "Invalid C2FieldSupportedValues::range.";
+                return false;
+            }
         }
-        d->values.resize(s.values.size());
         copyVector<uint64_t>(&d->values, s.values);
-        return Status::OK;
     }
+    return true;
 }
 
 // FieldSupportedValues::Range -> C2FieldSupportedValues::range's type
-void objcpy(
+bool objcpy(
         decltype(C2FieldSupportedValues::range)* d,
         const FieldSupportedValues::Range& s) {
     d->min.u64 = static_cast<uint64_t>(s.min);
@@ -157,19 +177,23 @@
     d->step.u64 = static_cast<uint64_t>(s.step);
     d->num.u64 = static_cast<uint64_t>(s.num);
     d->denom.u64 = static_cast<uint64_t>(s.denom);
+    return true;
 }
 
 // FieldSupportedValues -> C2FieldSupportedValues
-c2_status_t objcpy(C2FieldSupportedValues *d, const FieldSupportedValues &s) {
+bool objcpy(C2FieldSupportedValues *d, const FieldSupportedValues &s) {
     switch (s.type) {
     case FieldSupportedValues::Type::EMPTY:
         d->type = C2FieldSupportedValues::EMPTY;
-        return C2_OK;
+        break;
     case FieldSupportedValues::Type::RANGE:
         d->type = C2FieldSupportedValues::RANGE;
-        objcpy(&d->range, s.range);
+        if (!objcpy(&d->range, s.range)) {
+            LOG(ERROR) << "Invalid FieldSupportedValues::range.";
+            return false;
+        }
         d->values.resize(0);
-        return C2_OK;
+        break;
     default:
         switch (s.type) {
         case FieldSupportedValues::Type::VALUES:
@@ -179,22 +203,30 @@
             d->type = C2FieldSupportedValues::FLAGS;
             break;
         default:
-            d->type = static_cast<C2FieldSupportedValues::type_t>(s.typeOther);
-            // Copy all fields in this case
-            objcpy(&d->range, s.range);
+            LOG(DEBUG) << "Unrecognized FieldSupportedValues::Type "
+                       << "with underlying value " << underlying_value(s.type)
+                       << ".";
+            d->type = static_cast<C2FieldSupportedValues::type_t>(s.type);
+            if (!objcpy(&d->range, s.range)) {
+                LOG(ERROR) << "Invalid FieldSupportedValues::range.";
+                return false;
+            }
         }
         copyVector<uint64_t>(&d->values, s.values);
-        return C2_OK;
     }
+    return true;
 }
 
 } // unnamed namespace
 
 // C2FieldSupportedValuesQuery -> FieldSupportedValuesQuery
-Status objcpy(
+bool objcpy(
         FieldSupportedValuesQuery* d,
         const C2FieldSupportedValuesQuery& s) {
-    objcpy(&d->field, s.field());
+    if (!objcpy(&d->field, s.field())) {
+        LOG(ERROR) << "Invalid C2FieldSupportedValuesQuery::field.";
+        return false;
+    }
     switch (s.type()) {
     case C2FieldSupportedValuesQuery::POSSIBLE:
         d->type = FieldSupportedValuesQuery::Type::POSSIBLE;
@@ -203,15 +235,16 @@
         d->type = FieldSupportedValuesQuery::Type::CURRENT;
         break;
     default:
-        ALOGE("Unknown type of C2FieldSupportedValuesQuery: %u",
-                static_cast<unsigned>(s.type()));
-        return Status::BAD_VALUE;
+        LOG(DEBUG) << "Unrecognized C2FieldSupportedValuesQuery::type_t "
+                   << "with underlying value " << underlying_value(s.type())
+                   << ".";
+        d->type = static_cast<FieldSupportedValuesQuery::Type>(s.type());
     }
-    return Status::OK;
+    return true;
 }
 
 // FieldSupportedValuesQuery -> C2FieldSupportedValuesQuery
-c2_status_t objcpy(
+bool objcpy(
         C2FieldSupportedValuesQuery* d,
         const FieldSupportedValuesQuery& s) {
     C2FieldSupportedValuesQuery::type_t dType;
@@ -223,16 +256,17 @@
         dType = C2FieldSupportedValuesQuery::CURRENT;
         break;
     default:
-        ALOGE("Unknown type of FieldSupportedValuesQuery: %u",
-                static_cast<unsigned>(s.type));
-        return C2_BAD_VALUE;
+        LOG(DEBUG) << "Unrecognized FieldSupportedValuesQuery::Type "
+                   << "with underlying value " << underlying_value(s.type)
+                   << ".";
+        dType = static_cast<C2FieldSupportedValuesQuery::type_t>(s.type);
     }
     *d = C2FieldSupportedValuesQuery(C2ParamFieldBuilder(s.field), dType);
-    return C2_OK;
+    return true;
 }
 
 // C2FieldSupportedValuesQuery -> FieldSupportedValuesQueryResult
-Status objcpy(
+bool objcpy(
         FieldSupportedValuesQueryResult* d,
         const C2FieldSupportedValuesQuery& s) {
     d->status = static_cast<Status>(s.status);
@@ -241,20 +275,24 @@
 
 // FieldSupportedValuesQuery, FieldSupportedValuesQueryResult ->
 // C2FieldSupportedValuesQuery
-c2_status_t objcpy(
+bool objcpy(
         C2FieldSupportedValuesQuery* d,
         const FieldSupportedValuesQuery& sq,
         const FieldSupportedValuesQueryResult& sr) {
-    c2_status_t status = objcpy(d, sq);
-    if (status != C2_OK) {
-        return status;
+    if (!objcpy(d, sq)) {
+        LOG(ERROR) << "Invalid FieldSupportedValuesQuery.";
+        return false;
     }
     d->status = static_cast<c2_status_t>(sr.status);
-    return objcpy(&d->values, sr.values);
+    if (!objcpy(&d->values, sr.values)) {
+        LOG(ERROR) << "Invalid FieldSupportedValuesQueryResult::values.";
+        return false;
+    }
+    return true;
 }
 
 // C2Component::Traits -> IComponentStore::ComponentTraits
-Status objcpy(
+bool objcpy(
         IComponentStore::ComponentTraits *d,
         const C2Component::Traits &s) {
     d->name = s.name;
@@ -266,10 +304,19 @@
     case C2Component::DOMAIN_AUDIO:
         d->domain = IComponentStore::ComponentTraits::Domain::AUDIO;
         break;
-    default:
+    case C2Component::DOMAIN_IMAGE:
+        d->domain = IComponentStore::ComponentTraits::Domain::IMAGE;
+        break;
+    case C2Component::DOMAIN_OTHER:
         d->domain = IComponentStore::ComponentTraits::Domain::OTHER;
+        break;
+    default:
+        LOG(DEBUG) << "Unrecognized C2Component::domain_t "
+                   << "with underlying value " << underlying_value(s.domain)
+                   << ".";
+        d->domain = static_cast<IComponentStore::ComponentTraits::Domain>(
+                s.domain);
     }
-    d->domainOther = static_cast<uint32_t>(s.domain);
 
     switch (s.kind) {
     case C2Component::KIND_DECODER:
@@ -278,10 +325,16 @@
     case C2Component::KIND_ENCODER:
         d->kind = IComponentStore::ComponentTraits::Kind::ENCODER;
         break;
-    default:
+    case C2Component::KIND_OTHER:
         d->kind = IComponentStore::ComponentTraits::Kind::OTHER;
+        break;
+    default:
+        LOG(DEBUG) << "Unrecognized C2Component::kind_t "
+                   << "with underlying value " << underlying_value(s.kind)
+                   << ".";
+        d->kind = static_cast<IComponentStore::ComponentTraits::Kind>(
+                s.kind);
     }
-    d->kindOther = static_cast<uint32_t>(s.kind);
 
     d->rank = static_cast<uint32_t>(s.rank);
 
@@ -292,11 +345,11 @@
         --ix;
         d->aliases[ix] = s.aliases[ix];
     }
-    return Status::OK;
+    return true;
 }
 
 // ComponentTraits -> C2Component::Traits, std::unique_ptr<std::vector<std::string>>
-c2_status_t objcpy(
+bool objcpy(
         C2Component::Traits* d,
         std::unique_ptr<std::vector<std::string>>* aliasesBuffer,
         const IComponentStore::ComponentTraits& s) {
@@ -309,8 +362,17 @@
     case IComponentStore::ComponentTraits::Domain::AUDIO:
         d->domain = C2Component::DOMAIN_AUDIO;
         break;
+    case IComponentStore::ComponentTraits::Domain::IMAGE:
+        d->domain = C2Component::DOMAIN_IMAGE;
+        break;
+    case IComponentStore::ComponentTraits::Domain::OTHER:
+        d->domain = C2Component::DOMAIN_OTHER;
+        break;
     default:
-        d->domain = static_cast<C2Component::domain_t>(s.domainOther);
+        LOG(DEBUG) << "Unrecognized ComponentTraits::Domain "
+                   << "with underlying value " << underlying_value(s.domain)
+                   << ".";
+        d->domain = static_cast<C2Component::domain_t>(s.domain);
     }
 
     switch (s.kind) {
@@ -320,8 +382,14 @@
     case IComponentStore::ComponentTraits::Kind::ENCODER:
         d->kind = C2Component::KIND_ENCODER;
         break;
+    case IComponentStore::ComponentTraits::Kind::OTHER:
+        d->kind = C2Component::KIND_OTHER;
+        break;
     default:
-        d->kind = static_cast<C2Component::kind_t>(s.kindOther);
+        LOG(DEBUG) << "Unrecognized ComponentTraits::Kind "
+                   << "with underlying value " << underlying_value(s.kind)
+                   << ".";
+        d->kind = static_cast<C2Component::kind_t>(s.kind);
     }
 
     d->rank = static_cast<C2Component::rank_t>(s.rank);
@@ -336,52 +404,55 @@
         (**aliasesBuffer)[i] = s.aliases[i].c_str();
         d->aliases[i] = (**aliasesBuffer)[i].c_str();
     }
-    return C2_OK;
+    return true;
 }
 
 namespace /* unnamed */ {
 
 // C2ParamFieldValues -> ParamFieldValues
-Status objcpy(ParamFieldValues *d, const C2ParamFieldValues &s) {
-    objcpy(&d->paramOrField, s.paramOrField);
+bool objcpy(ParamFieldValues *d, const C2ParamFieldValues &s) {
+    if (!objcpy(&d->paramOrField, s.paramOrField)) {
+        LOG(ERROR) << "Invalid C2ParamFieldValues::paramOrField.";
+        return false;
+    }
     if (s.values) {
         d->values.resize(1);
-        return objcpy(&d->values[0], *s.values);
+        if (!objcpy(&d->values[0], *s.values)) {
+            LOG(ERROR) << "Invalid C2ParamFieldValues::values.";
+            return false;
+        }
+        return true;
     }
     d->values.resize(0);
-    return Status::OK;
+    return true;
 }
 
 // ParamFieldValues -> C2ParamFieldValues
-c2_status_t objcpy(C2ParamFieldValues *d, const ParamFieldValues &s) {
+bool objcpy(C2ParamFieldValues *d, const ParamFieldValues &s) {
     d->paramOrField = C2ParamFieldBuilder(s.paramOrField);
     if (s.values.size() == 1) {
         d->values = std::make_unique<C2FieldSupportedValues>();
-        return objcpy(d->values.get(), s.values[0]);
+        if (!objcpy(d->values.get(), s.values[0])) {
+            LOG(ERROR) << "Invalid ParamFieldValues::values.";
+            return false;
+        }
+        return true;
     } else if (s.values.size() == 0) {
         d->values.reset();
-        return C2_OK;
+        return true;
     }
-    ALOGE("Multiple FieldSupportedValues objects. "
-            "(Only one is allowed.)");
-    return C2_BAD_VALUE;
+    LOG(ERROR) << "Invalid ParamFieldValues: "
+                  "Two or more FieldSupportedValues objects exist in "
+                  "ParamFieldValues. "
+                  "Only zero or one is allowed.";
+    return false;
 }
 
 } // unnamed namespace
 
 // C2SettingResult -> SettingResult
-Status objcpy(SettingResult *d, const C2SettingResult &s) {
-    d->failureOther = static_cast<uint32_t>(s.failure);
+bool objcpy(SettingResult *d, const C2SettingResult &s) {
     switch (s.failure) {
-    case C2SettingResult::READ_ONLY:
-        d->failure = SettingResult::Failure::READ_ONLY;
-        break;
-    case C2SettingResult::MISMATCH:
-        d->failure = SettingResult::Failure::MISMATCH;
-        break;
-    case C2SettingResult::BAD_VALUE:
-        d->failure = SettingResult::Failure::BAD_VALUE;
-        break;
     case C2SettingResult::BAD_TYPE:
         d->failure = SettingResult::Failure::BAD_TYPE;
         break;
@@ -391,53 +462,61 @@
     case C2SettingResult::BAD_INDEX:
         d->failure = SettingResult::Failure::BAD_INDEX;
         break;
+    case C2SettingResult::READ_ONLY:
+        d->failure = SettingResult::Failure::READ_ONLY;
+        break;
+    case C2SettingResult::MISMATCH:
+        d->failure = SettingResult::Failure::MISMATCH;
+        break;
+    case C2SettingResult::BAD_VALUE:
+        d->failure = SettingResult::Failure::BAD_VALUE;
+        break;
     case C2SettingResult::CONFLICT:
         d->failure = SettingResult::Failure::CONFLICT;
         break;
     case C2SettingResult::UNSUPPORTED:
         d->failure = SettingResult::Failure::UNSUPPORTED;
         break;
+    case C2SettingResult::INFO_BAD_VALUE:
+        d->failure = SettingResult::Failure::INFO_BAD_VALUE;
+        break;
     case C2SettingResult::INFO_CONFLICT:
         d->failure = SettingResult::Failure::INFO_CONFLICT;
         break;
     default:
-        d->failure = SettingResult::Failure::OTHER;
+        LOG(DEBUG) << "Unrecognized C2SettingResult::Failure "
+                   << "with underlying value " << underlying_value(s.failure)
+                   << ".";
+        d->failure = static_cast<SettingResult::Failure>(s.failure);
     }
-    Status status = objcpy(&d->field, s.field);
-    if (status != Status::OK) {
-        return status;
+    if (!objcpy(&d->field, s.field)) {
+        LOG(ERROR) << "Invalid C2SettingResult::field.";
+        return false;
     }
     d->conflicts.resize(s.conflicts.size());
     size_t i = 0;
     for (const C2ParamFieldValues& sConflict : s.conflicts) {
         ParamFieldValues &dConflict = d->conflicts[i++];
-        status = objcpy(&dConflict, sConflict);
-        if (status != Status::OK) {
-            return status;
+        if (!objcpy(&dConflict, sConflict)) {
+            LOG(ERROR) << "Invalid C2SettingResult::conflicts["
+                       << i - 1 << "].";
+            return false;
         }
     }
-    return Status::OK;
+    return true;
 }
 
 // SettingResult -> std::unique_ptr<C2SettingResult>
-c2_status_t objcpy(std::unique_ptr<C2SettingResult> *d, const SettingResult &s) {
+bool objcpy(std::unique_ptr<C2SettingResult> *d, const SettingResult &s) {
     *d = std::unique_ptr<C2SettingResult>(new C2SettingResult {
             .field = C2ParamFieldValues(C2ParamFieldBuilder()) });
     if (!*d) {
-        return C2_NO_MEMORY;
+        LOG(ERROR) << "No memory for C2SettingResult.";
+        return false;
     }
 
     // failure
     switch (s.failure) {
-    case SettingResult::Failure::READ_ONLY:
-        (*d)->failure = C2SettingResult::READ_ONLY;
-        break;
-    case SettingResult::Failure::MISMATCH:
-        (*d)->failure = C2SettingResult::MISMATCH;
-        break;
-    case SettingResult::Failure::BAD_VALUE:
-        (*d)->failure = C2SettingResult::BAD_VALUE;
-        break;
     case SettingResult::Failure::BAD_TYPE:
         (*d)->failure = C2SettingResult::BAD_TYPE;
         break;
@@ -447,23 +526,38 @@
     case SettingResult::Failure::BAD_INDEX:
         (*d)->failure = C2SettingResult::BAD_INDEX;
         break;
+    case SettingResult::Failure::READ_ONLY:
+        (*d)->failure = C2SettingResult::READ_ONLY;
+        break;
+    case SettingResult::Failure::MISMATCH:
+        (*d)->failure = C2SettingResult::MISMATCH;
+        break;
+    case SettingResult::Failure::BAD_VALUE:
+        (*d)->failure = C2SettingResult::BAD_VALUE;
+        break;
     case SettingResult::Failure::CONFLICT:
         (*d)->failure = C2SettingResult::CONFLICT;
         break;
     case SettingResult::Failure::UNSUPPORTED:
         (*d)->failure = C2SettingResult::UNSUPPORTED;
         break;
+    case SettingResult::Failure::INFO_BAD_VALUE:
+        (*d)->failure = C2SettingResult::INFO_BAD_VALUE;
+        break;
     case SettingResult::Failure::INFO_CONFLICT:
         (*d)->failure = C2SettingResult::INFO_CONFLICT;
         break;
     default:
-        (*d)->failure = static_cast<C2SettingResult::Failure>(s.failureOther);
+        LOG(DEBUG) << "Unrecognized SettingResult::Failure "
+                   << "with underlying value " << underlying_value(s.failure)
+                   << ".";
+        (*d)->failure = static_cast<C2SettingResult::Failure>(s.failure);
     }
 
     // field
-    c2_status_t status = objcpy(&(*d)->field, s.field);
-    if (status != C2_OK) {
-        return status;
+    if (!objcpy(&(*d)->field, s.field)) {
+        LOG(ERROR) << "Invalid SettingResult::field.";
+        return false;
     }
 
     // conflicts
@@ -472,26 +566,26 @@
     for (const ParamFieldValues& sConflict : s.conflicts) {
         (*d)->conflicts.emplace_back(
                 C2ParamFieldValues{ C2ParamFieldBuilder(), nullptr });
-        status = objcpy(&(*d)->conflicts.back(), sConflict);
-        if (status != C2_OK) {
-            return status;
+        if (!objcpy(&(*d)->conflicts.back(), sConflict)) {
+            LOG(ERROR) << "Invalid SettingResult::conflicts.";
+            return false;
         }
     }
-    return C2_OK;
+    return true;
 }
 
 // C2ParamDescriptor -> ParamDescriptor
-Status objcpy(ParamDescriptor *d, const C2ParamDescriptor &s) {
+bool objcpy(ParamDescriptor *d, const C2ParamDescriptor &s) {
     d->index = static_cast<ParamIndex>(s.index());
     d->attrib = static_cast<hidl_bitfield<ParamDescriptor::Attrib>>(
             _C2ParamInspector::GetAttrib(s));
     d->name = s.name();
     copyVector<uint32_t>(&d->dependencies, s.dependencies());
-    return Status::OK;
+    return true;
 }
 
 // ParamDescriptor -> C2ParamDescriptor
-c2_status_t objcpy(std::shared_ptr<C2ParamDescriptor> *d, const ParamDescriptor &s) {
+bool objcpy(std::shared_ptr<C2ParamDescriptor> *d, const ParamDescriptor &s) {
     std::vector<C2Param::Index> dDependencies;
     dDependencies.reserve(s.dependencies.size());
     for (const ParamIndex& sDependency : s.dependencies) {
@@ -502,11 +596,11 @@
             static_cast<C2ParamDescriptor::attrib_t>(s.attrib),
             C2String(s.name.c_str()),
             std::move(dDependencies));
-    return C2_OK;
+    return true;
 }
 
 // C2StructDescriptor -> StructDescriptor
-Status objcpy(StructDescriptor *d, const C2StructDescriptor &s) {
+bool objcpy(StructDescriptor *d, const C2StructDescriptor &s) {
     d->type = static_cast<ParamIndex>(s.coreIndex().coreIndex());
     d->fields.resize(s.numFields());
     size_t i = 0;
@@ -518,7 +612,7 @@
                 _C2ParamInspector::GetSize(sField));
         dField.type = static_cast<hidl_bitfield<FieldDescriptor::Type>>(
                 sField.type());
-        dField.length = static_cast<uint32_t>(sField.extent());
+        dField.extent = static_cast<uint32_t>(sField.extent());
         dField.name = static_cast<hidl_string>(sField.name());
         const auto& sNamedValues = sField.namedValues();
         dField.namedValues.resize(sNamedValues.size());
@@ -530,18 +624,18 @@
                     sNamedValue.second.u64);
         }
     }
-    return Status::OK;
+    return true;
 }
 
 // StructDescriptor -> C2StructDescriptor
-c2_status_t objcpy(std::unique_ptr<C2StructDescriptor> *d, const StructDescriptor &s) {
+bool objcpy(std::unique_ptr<C2StructDescriptor> *d, const StructDescriptor &s) {
     C2Param::CoreIndex dIndex = C2Param::CoreIndex(static_cast<uint32_t>(s.type));
     std::vector<C2FieldDescriptor> dFields;
     dFields.reserve(s.fields.size());
     for (const auto &sField : s.fields) {
         C2FieldDescriptor dField = {
             static_cast<uint32_t>(sField.type),
-            sField.length,
+            sField.extent,
             sField.name,
             sField.fieldId.offset,
             sField.fieldId.size };
@@ -557,7 +651,7 @@
     }
     *d = std::make_unique<C2StructDescriptor>(
             _C2ParamInspector::CreateStructDescriptor(dIndex, std::move(dFields)));
-    return C2_OK;
+    return true;
 }
 
 namespace /* unnamed */ {
@@ -565,14 +659,14 @@
 // Find or add a hidl BaseBlock object from a given C2Handle* to a list and an
 // associated map.
 // Note: The handle is not cloned.
-Status _addBaseBlock(
+bool _addBaseBlock(
         uint32_t* index,
         const C2Handle* handle,
         std::list<BaseBlock>* baseBlocks,
         std::map<const void*, uint32_t>* baseBlockIndices) {
     if (!handle) {
-        ALOGE("addBaseBlock called on a null C2Handle.");
-        return Status::BAD_VALUE;
+        LOG(ERROR) << "addBaseBlock called on a null C2Handle.";
+        return false;
     }
     auto it = baseBlockIndices->find(handle);
     if (it != baseBlockIndices->end()) {
@@ -583,26 +677,25 @@
         baseBlocks->emplace_back();
 
         BaseBlock &dBaseBlock = baseBlocks->back();
-        dBaseBlock.type = BaseBlock::Type::NATIVE;
         // This does not clone the handle.
-        dBaseBlock.nativeBlock =
-                reinterpret_cast<const native_handle_t*>(handle);
+        dBaseBlock.nativeBlock(
+                reinterpret_cast<const native_handle_t*>(handle));
 
     }
-    return Status::OK;
+    return true;
 }
 
 // Find or add a hidl BaseBlock object from a given BufferPoolData to a list and
 // an associated map.
-Status _addBaseBlock(
+bool _addBaseBlock(
         uint32_t* index,
         const std::shared_ptr<BufferPoolData> bpData,
         BufferPoolSender* bufferPoolSender,
         std::list<BaseBlock>* baseBlocks,
         std::map<const void*, uint32_t>* baseBlockIndices) {
     if (!bpData) {
-        ALOGE("addBaseBlock called on a null BufferPoolData.");
-        return Status::BAD_VALUE;
+        LOG(ERROR) << "addBaseBlock called on a null BufferPoolData.";
+        return false;
     }
     auto it = baseBlockIndices->find(bpData.get());
     if (it != baseBlockIndices->end()) {
@@ -613,24 +706,26 @@
         baseBlocks->emplace_back();
 
         BaseBlock &dBaseBlock = baseBlocks->back();
-        dBaseBlock.type = BaseBlock::Type::POOLED;
 
         if (bufferPoolSender) {
+            BufferStatusMessage pooledBlock;
             ResultStatus bpStatus = bufferPoolSender->send(
                     bpData,
-                    &dBaseBlock.pooledBlock);
+                    &pooledBlock);
 
             if (bpStatus != ResultStatus::OK) {
-                ALOGE("Failed to send buffer with BufferPool. Error: %d.",
-                        static_cast<int>(bpStatus));
-                return Status::BAD_VALUE;
+                LOG(ERROR) << "Failed to send buffer with BufferPool. Error: "
+                           << static_cast<int32_t>(bpStatus)
+                           << ".";
+                return false;
             }
+            dBaseBlock.pooledBlock(pooledBlock);
         }
     }
-    return Status::OK;
+    return true;
 }
 
-Status addBaseBlock(
+bool addBaseBlock(
         uint32_t* index,
         const C2Handle* handle,
         const std::shared_ptr<const _C2BlockPoolData>& blockPoolData,
@@ -649,8 +744,8 @@
             std::shared_ptr<BufferPoolData> bpData;
             if (!_C2BlockFactory::GetBufferPoolData(blockPoolData, &bpData)
                     || !bpData) {
-                ALOGE("BufferPoolData unavailable in a block.");
-                return Status::BAD_VALUE;
+                LOG(ERROR) << "BufferPoolData unavailable in a block.";
+                return false;
             }
             return _addBaseBlock(
                     index, bpData,
@@ -662,69 +757,76 @@
                 index, handle,
                 baseBlocks, baseBlockIndices);
     default:
-        ALOGE("Unknown C2BlockPoolData type.");
-        return Status::BAD_VALUE;
+        LOG(ERROR) << "Unknown C2BlockPoolData type.";
+        return false;
     }
 }
 
 // C2Fence -> hidl_handle
 // Note: File descriptors are not duplicated. The original file descriptor must
 // not be closed before the transaction is complete.
-Status objcpy(hidl_handle* d, const C2Fence& s) {
+bool objcpy(hidl_handle* d, const C2Fence& s) {
     (void)s; // TODO: implement s.fd()
     int fenceFd = -1;
     d->setTo(nullptr);
     if (fenceFd >= 0) {
         native_handle_t *handle = native_handle_create(1, 0);
         if (!handle) {
-            return Status::NO_MEMORY;
+            LOG(ERROR) << "Failed to create a native handle.";
+            return false;
         }
         handle->data[0] = fenceFd;
         d->setTo(handle, true /* owns */);
     }
-    return Status::OK;
+    return true;
 }
 
 // C2ConstLinearBlock -> Block
 // Note: Native handles are not duplicated. The original handles must not be
 // closed before the transaction is complete.
-Status objcpy(Block* d, const C2ConstLinearBlock& s,
+bool objcpy(Block* d, const C2ConstLinearBlock& s,
         BufferPoolSender* bufferPoolSender,
         std::list<BaseBlock>* baseBlocks,
         std::map<const void*, uint32_t>* baseBlockIndices) {
     std::shared_ptr<const _C2BlockPoolData> bpData =
             _C2BlockFactory::GetLinearBlockPoolData(s);
-    Status status = addBaseBlock(&d->index, s.handle(), bpData,
-            bufferPoolSender, baseBlocks, baseBlockIndices);
-    if (status != Status::OK) {
-        return status;
+    if (!addBaseBlock(&d->index, s.handle(), bpData,
+            bufferPoolSender, baseBlocks, baseBlockIndices)) {
+        LOG(ERROR) << "Invalid block data in C2ConstLinearBlock.";
+        return false;
     }
 
     // Create the metadata.
     C2Hidl_RangeInfo dRangeInfo;
     dRangeInfo.offset = static_cast<uint32_t>(s.offset());
     dRangeInfo.length = static_cast<uint32_t>(s.size());
-    status = createParamsBlob(&d->meta,
-            std::vector<C2Param*>{ &dRangeInfo });
-    if (status != Status::OK) {
-        return Status::BAD_VALUE;
+    if (!createParamsBlob(&d->meta, std::vector<C2Param*>{ &dRangeInfo })) {
+        LOG(ERROR) << "Invalid range info in C2ConstLinearBlock.";
+        return false;
     }
 
     // Copy the fence
-    return objcpy(&d->fence, s.fence());
+    if (!objcpy(&d->fence, s.fence())) {
+        LOG(ERROR) << "Invalid C2ConstLinearBlock::fence.";
+        return false;
+    }
+    return true;
 }
 
 // C2ConstGraphicBlock -> Block
 // Note: Native handles are not duplicated. The original handles must not be
 // closed before the transaction is complete.
-Status objcpy(Block* d, const C2ConstGraphicBlock& s,
+bool objcpy(Block* d, const C2ConstGraphicBlock& s,
         BufferPoolSender* bufferPoolSender,
         std::list<BaseBlock>* baseBlocks,
         std::map<const void*, uint32_t>* baseBlockIndices) {
     std::shared_ptr<const _C2BlockPoolData> bpData =
             _C2BlockFactory::GetGraphicBlockPoolData(s);
-    Status status = addBaseBlock(&d->index, s.handle(), bpData,
-            bufferPoolSender, baseBlocks, baseBlockIndices);
+    if (!addBaseBlock(&d->index, s.handle(), bpData,
+            bufferPoolSender, baseBlocks, baseBlockIndices)) {
+        LOG(ERROR) << "Invalid block data in C2ConstGraphicBlock.";
+        return false;
+    }
 
     // Create the metadata.
     C2Hidl_RectInfo dRectInfo;
@@ -733,62 +835,70 @@
     dRectInfo.top = static_cast<uint32_t>(sRect.top);
     dRectInfo.width = static_cast<uint32_t>(sRect.width);
     dRectInfo.height = static_cast<uint32_t>(sRect.height);
-    status = createParamsBlob(&d->meta,
-            std::vector<C2Param*>{ &dRectInfo });
-    if (status != Status::OK) {
-        return Status::BAD_VALUE;
+    if (!createParamsBlob(&d->meta, std::vector<C2Param*>{ &dRectInfo })) {
+        LOG(ERROR) << "Invalid rect info in C2ConstGraphicBlock.";
+        return false;
     }
 
     // Copy the fence
-    return objcpy(&d->fence, s.fence());
+    if (!objcpy(&d->fence, s.fence())) {
+        LOG(ERROR) << "Invalid C2ConstGraphicBlock::fence.";
+        return false;
+    }
+    return true;
 }
 
 // C2BufferData -> Buffer
 // This function only fills in d->blocks.
-Status objcpy(Buffer* d, const C2BufferData& s,
+bool objcpy(Buffer* d, const C2BufferData& s,
         BufferPoolSender* bufferPoolSender,
         std::list<BaseBlock>* baseBlocks,
         std::map<const void*, uint32_t>* baseBlockIndices) {
-    Status status;
     d->blocks.resize(
             s.linearBlocks().size() +
             s.graphicBlocks().size());
     size_t i = 0;
     for (const C2ConstLinearBlock& linearBlock : s.linearBlocks()) {
         Block& dBlock = d->blocks[i++];
-        status = objcpy(
+        if (!objcpy(
                 &dBlock, linearBlock,
-                bufferPoolSender, baseBlocks, baseBlockIndices);
-        if (status != Status::OK) {
-            return status;
+                bufferPoolSender, baseBlocks, baseBlockIndices)) {
+            LOG(ERROR) << "Invalid C2BufferData::linearBlocks. "
+                       << "(Destination index = " << i - 1 << ".)";
+            return false;
         }
     }
     for (const C2ConstGraphicBlock& graphicBlock : s.graphicBlocks()) {
         Block& dBlock = d->blocks[i++];
-        status = objcpy(
+        if (!objcpy(
                 &dBlock, graphicBlock,
-                bufferPoolSender, baseBlocks, baseBlockIndices);
-        if (status != Status::OK) {
-            return status;
+                bufferPoolSender, baseBlocks, baseBlockIndices)) {
+            LOG(ERROR) << "Invalid C2BufferData::graphicBlocks. "
+                       << "(Destination index = " << i - 1 << ".)";
+            return false;
         }
     }
-    return Status::OK;
+    return true;
 }
 
 // C2Buffer -> Buffer
-Status objcpy(Buffer* d, const C2Buffer& s,
+bool objcpy(Buffer* d, const C2Buffer& s,
         BufferPoolSender* bufferPoolSender,
         std::list<BaseBlock>* baseBlocks,
         std::map<const void*, uint32_t>* baseBlockIndices) {
-    Status status = createParamsBlob(&d->info, s.info());
-    if (status != Status::OK) {
-        return status;
+    if (!createParamsBlob(&d->info, s.info())) {
+        LOG(ERROR) << "Invalid C2Buffer::info.";
+        return false;
     }
-    return objcpy(d, s.data(), bufferPoolSender, baseBlocks, baseBlockIndices);
+    if (!objcpy(d, s.data(), bufferPoolSender, baseBlocks, baseBlockIndices)) {
+        LOG(ERROR) << "Invalid C2Buffer::data.";
+        return false;
+    }
+    return true;
 }
 
 // C2InfoBuffer -> InfoBuffer
-Status objcpy(InfoBuffer* d, const C2InfoBuffer& s,
+bool objcpy(InfoBuffer* d, const C2InfoBuffer& s,
         BufferPoolSender* bufferPoolSender,
         std::list<BaseBlock>* baseBlocks,
         std::map<const void*, uint32_t>* baseBlockIndices) {
@@ -798,24 +908,21 @@
     (void)bufferPoolSender;
     (void)baseBlocks;
     (void)baseBlockIndices;
-    return Status::OK;
-    /*
-    // Stub implementation that may work in the future.
-    d->index = static_cast<uint32_t>(s.index());
-    d->buffer.info.resize(0);
-    return objcpy(&d->buffer, s.data(), baseBlocks, baseBlockIndices);
-    */
+    LOG(INFO) << "InfoBuffer not implemented.";
+    return true;
 }
 
 // C2FrameData -> FrameData
-Status objcpy(FrameData* d, const C2FrameData& s,
+bool objcpy(FrameData* d, const C2FrameData& s,
         BufferPoolSender* bufferPoolSender,
         std::list<BaseBlock>* baseBlocks,
         std::map<const void*, uint32_t>* baseBlockIndices) {
     d->flags = static_cast<hidl_bitfield<FrameData::Flags>>(s.flags);
-    objcpy(&d->ordinal, s.ordinal);
+    if (!objcpy(&d->ordinal, s.ordinal)) {
+        LOG(ERROR) << "Invalid C2FrameData::ordinal.";
+        return false;
+    }
 
-    Status status;
     d->buffers.resize(s.buffers.size());
     size_t i = 0;
     for (const std::shared_ptr<C2Buffer>& sBuffer : s.buffers) {
@@ -827,17 +934,18 @@
             dBuffer.blocks.resize(0);
             continue;
         }
-        status = objcpy(
+        if (!objcpy(
                 &dBuffer, *sBuffer,
-                bufferPoolSender, baseBlocks, baseBlockIndices);
-        if (status != Status::OK) {
-            return status;
+                bufferPoolSender, baseBlocks, baseBlockIndices)) {
+            LOG(ERROR) << "Invalid C2FrameData::buffers["
+                       << i - 1 << "].";
+            return false;
         }
     }
 
-    status = createParamsBlob(&d->configUpdate, s.configUpdate);
-    if (status != Status::OK) {
-        return status;
+    if (!createParamsBlob(&d->configUpdate, s.configUpdate)) {
+        LOG(ERROR) << "Invalid C2FrameData::configUpdate.";
+        return false;
     }
 
     d->infoBuffers.resize(s.infoBuffers.size());
@@ -845,17 +953,19 @@
     for (const std::shared_ptr<C2InfoBuffer>& sInfoBuffer : s.infoBuffers) {
         InfoBuffer& dInfoBuffer = d->infoBuffers[i++];
         if (!sInfoBuffer) {
-            ALOGE("Null C2InfoBuffer");
-            return Status::BAD_VALUE;
+            LOG(ERROR) << "Null C2FrameData::infoBuffers["
+                       << i - 1 << "].";
+            return false;
         }
-        status = objcpy(&dInfoBuffer, *sInfoBuffer,
-                bufferPoolSender, baseBlocks, baseBlockIndices);
-        if (status != Status::OK) {
-            return status;
+        if (!objcpy(&dInfoBuffer, *sInfoBuffer,
+                bufferPoolSender, baseBlocks, baseBlockIndices)) {
+            LOG(ERROR) << "Invalid C2FrameData::infoBuffers["
+                       << i - 1 << "].";
+            return false;
         }
     }
 
-    return status;
+    return true;
 }
 
 } // unnamed namespace
@@ -885,7 +995,7 @@
         const std::shared_ptr<BufferPoolData>& bpData,
         BufferStatusMessage* bpMessage) {
     if (!mReceiverManager) {
-        ALOGE("No access to receiver's BufferPool.");
+        LOG(ERROR) << "No access to receiver's BufferPool.";
         return ResultStatus::NOT_FOUND;
     }
     ResultStatus rs;
@@ -893,7 +1003,7 @@
     if (!mSenderManager) {
         mSenderManager = ClientManager::getInstance();
         if (!mSenderManager) {
-            ALOGE("Failed to retrieve local BufferPool ClientManager.");
+            LOG(ERROR) << "Failed to retrieve local BufferPool ClientManager.";
             return ResultStatus::CRITICAL_ERROR;
         }
     }
@@ -915,11 +1025,11 @@
                                             connectionId,
                                             &receiverConnectionId);
         if ((rs != ResultStatus::OK) && (rs != ResultStatus::ALREADY_EXISTS)) {
-            ALOGW("registerSender -- returned error: %d.",
-                    static_cast<int>(rs));
+            LOG(WARNING) << "registerSender -- returned error: "
+                         << static_cast<int32_t>(rs)
+                         << ".";
             return rs;
         } else {
-            ALOGV("registerSender -- succeeded.");
             mReceiverConnectionId = receiverConnectionId;
         }
     }
@@ -929,12 +1039,13 @@
     rs = mSenderManager->postSend(
             mReceiverConnectionId, bpData, &transactionId, &timestampUs);
     if (rs != ResultStatus::OK) {
-        ALOGE("ClientManager::postSend -- returned error: %d.",
-                static_cast<int>(rs));
+        LOG(ERROR) << "ClientManager::postSend -- returned error: "
+                   << static_cast<int32_t>(rs)
+                   << ".";
         return rs;
     }
     if (!bpMessage) {
-        ALOGE("Null output parameter for BufferStatusMessage.");
+        LOG(ERROR) << "Null output parameter for BufferStatusMessage.";
         return ResultStatus::CRITICAL_ERROR;
     }
     bpMessage->connectionId = mReceiverConnectionId;
@@ -946,12 +1057,10 @@
 }
 
 // std::list<std::unique_ptr<C2Work>> -> WorkBundle
-Status objcpy(
+bool objcpy(
         WorkBundle* d,
         const std::list<std::unique_ptr<C2Work>>& s,
         BufferPoolSender* bufferPoolSender) {
-    Status status = Status::OK;
-
     // baseBlocks holds a list of BaseBlock objects that Blocks can refer to.
     std::list<BaseBlock> baseBlocks;
 
@@ -971,63 +1080,80 @@
     for (const std::unique_ptr<C2Work>& sWork : s) {
         Work &dWork = d->works[i++];
         if (!sWork) {
-            ALOGW("Null C2Work encountered.");
+            LOG(WARNING) << "Null C2Work encountered.";
             continue;
         }
-        status = objcpy(&dWork.input, sWork->input,
-                bufferPoolSender, &baseBlocks, &baseBlockIndices);
-        if (status != Status::OK) {
-            return status;
+
+        // chain info is not in use currently.
+
+        // input
+        if (!objcpy(&dWork.input, sWork->input,
+                bufferPoolSender, &baseBlocks, &baseBlockIndices)) {
+            LOG(ERROR) << "Invalid C2Work::input.";
+            return false;
         }
+
+        // worklets
         if (sWork->worklets.size() == 0) {
-            ALOGW("Work with no worklets.");
+            LOG(DEBUG) << "Work with no worklets.";
         } else {
-            if (sWork->worklets.size() > 1) {
-                ALOGW("Work with multiple worklets. "
-                        "Only the first worklet will be marshalled.");
-            }
-            if (!sWork->worklets.front()) {
-                ALOGE("Null worklet encountered.");
-                return Status::BAD_VALUE;
-            }
-
-            // Parcel the first worklet.
-            const C2Worklet &sWorklet = *sWork->worklets.front();
-            Worklet &dWorklet = dWork.worklet;
-
-            dWorklet.tunings.resize(sWorklet.tunings.size());
+            // Parcel the worklets.
+            hidl_vec<Worklet> &dWorklets = dWork.worklets;
+            dWorklets.resize(sWork->worklets.size());
             size_t j = 0;
-            for (const std::unique_ptr<C2Tuning>& sTuning : sWorklet.tunings) {
-                status = createParamsBlob(
-                        &dWorklet.tunings[j++],
-                        std::vector<C2Param*>
-                        { reinterpret_cast<C2Param*>(sTuning.get()) });
-                if (status != Status::OK) {
-                    return status;
+            for (const std::unique_ptr<C2Worklet>& sWorklet : sWork->worklets)
+            {
+                if (!sWorklet) {
+                    LOG(WARNING) << "Null C2Work::worklets["
+                                 << j << "].";
+                    continue;
                 }
-            }
+                Worklet &dWorklet = dWorklets[j++];
 
-            dWorklet.failures.resize(sWorklet.failures.size());
-            j = 0;
-            for (const std::unique_ptr<C2SettingResult>& sFailure :
-                    sWorklet.failures) {
-                if (!sFailure) {
-                    ALOGE("Null C2SettingResult");
-                    return Status::BAD_VALUE;
-                }
-                status = objcpy(&dWorklet.failures[j++], *sFailure);
-                if (status != Status::OK) {
-                    return status;
-                }
-            }
+                // component id
+                dWorklet.componentId = static_cast<uint32_t>(
+                        sWorklet->component);
 
-            status = objcpy(&dWorklet.output, sWorklet.output,
-                    bufferPoolSender, &baseBlocks, &baseBlockIndices);
-            if (status != Status::OK) {
-                return status;
+                // tunings
+                if (!createParamsBlob(&dWorklet.tunings, sWorklet->tunings)) {
+                    LOG(ERROR) << "Invalid C2Work::worklets["
+                               << j - 1 << "]->tunings.";
+                    return false;
+                }
+
+                // failures
+                dWorklet.failures.resize(sWorklet->failures.size());
+                size_t k = 0;
+                for (const std::unique_ptr<C2SettingResult>& sFailure :
+                        sWorklet->failures) {
+                    if (!sFailure) {
+                        LOG(WARNING) << "Null C2Work::worklets["
+                                     << j - 1 << "]->failures["
+                                     << k << "].";
+                        continue;
+                    }
+                    if (!objcpy(&dWorklet.failures[k++], *sFailure)) {
+                        LOG(ERROR) << "Invalid C2Work::worklets["
+                                   << j - 1 << "]->failures["
+                                   << k - 1 << "].";
+                        return false;
+                    }
+                }
+
+                // output
+                if (!objcpy(&dWorklet.output, sWorklet->output,
+                        bufferPoolSender, &baseBlocks, &baseBlockIndices)) {
+                    LOG(ERROR) << "Invalid C2Work::worklets["
+                               << j - 1 << "]->output.";
+                    return false;
+                }
             }
         }
-        dWork.workletProcessed = sWork->workletsProcessed > 0;
+
+        // worklets processed
+        dWork.workletsProcessed = sWork->workletsProcessed;
+
+        // result
         dWork.result = static_cast<Status>(sWork->result);
     }
 
@@ -1040,7 +1166,7 @@
         }
     }
 
-    return Status::OK;
+    return true;
 }
 
 namespace /* unnamed */ {
@@ -1058,15 +1184,15 @@
 // hidl_handle -> C2Fence
 // Note: File descriptors are not duplicated. The original file descriptor must
 // not be closed before the transaction is complete.
-c2_status_t objcpy(C2Fence* d, const hidl_handle& s) {
+bool objcpy(C2Fence* d, const hidl_handle& s) {
     // TODO: Implement.
     (void)s;
     *d = C2Fence();
-    return C2_OK;
+    return true;
 }
 
 // C2LinearBlock, vector<C2Param*>, C2Fence -> C2Buffer
-c2_status_t createLinearBuffer(
+bool createLinearBuffer(
         std::shared_ptr<C2Buffer>* buffer,
         const std::shared_ptr<C2LinearBlock>& block,
         const std::vector<C2Param*>& meta,
@@ -1074,12 +1200,12 @@
     // Check the block meta. It should have exactly 1 C2Info:
     // C2Hidl_RangeInfo.
     if ((meta.size() != 1) || !meta[0]) {
-        ALOGE("Invalid block metadata for ion block.");
-        return C2_BAD_VALUE;
+        LOG(ERROR) << "Invalid C2LinearBlock::meta.";
+        return false;
     }
     if (meta[0]->size() != sizeof(C2Hidl_RangeInfo)) {
-        ALOGE("Invalid block metadata for ion block: range.");
-        return C2_BAD_VALUE;
+        LOG(ERROR) << "Invalid range info in C2LinearBlock.";
+        return false;
     }
     C2Hidl_RangeInfo *rangeInfo =
             reinterpret_cast<C2Hidl_RangeInfo*>(meta[0]);
@@ -1089,14 +1215,14 @@
             rangeInfo->offset, rangeInfo->length,
             fence));
     if (!(*buffer)) {
-        ALOGE("Cannot create a linear buffer.");
-        return C2_BAD_VALUE;
+        LOG(ERROR) << "CreateLinearBuffer failed.";
+        return false;
     }
-    return C2_OK;
+    return true;
 }
 
 // C2GraphicBlock, vector<C2Param*>, C2Fence -> C2Buffer
-c2_status_t createGraphicBuffer(
+bool createGraphicBuffer(
         std::shared_ptr<C2Buffer>* buffer,
         const std::shared_ptr<C2GraphicBlock>& block,
         const std::vector<C2Param*>& meta,
@@ -1104,12 +1230,12 @@
     // Check the block meta. It should have exactly 1 C2Info:
     // C2Hidl_RectInfo.
     if ((meta.size() != 1) || !meta[0]) {
-        ALOGE("Invalid block metadata for graphic block.");
-        return C2_BAD_VALUE;
+        LOG(ERROR) << "Invalid C2GraphicBlock::meta.";
+        return false;
     }
     if (meta[0]->size() != sizeof(C2Hidl_RectInfo)) {
-        ALOGE("Invalid block metadata for graphic block: crop rect.");
-        return C2_BAD_VALUE;
+        LOG(ERROR) << "Invalid rect info in C2GraphicBlock.";
+        return false;
     }
     C2Hidl_RectInfo *rectInfo =
             reinterpret_cast<C2Hidl_RectInfo*>(meta[0]);
@@ -1120,136 +1246,144 @@
             at(rectInfo->left, rectInfo->top),
             fence));
     if (!(*buffer)) {
-        ALOGE("Cannot create a graphic buffer.");
-        return C2_BAD_VALUE;
+        LOG(ERROR) << "CreateGraphicBuffer failed.";
+        return false;
     }
-    return C2_OK;
+    return true;
 }
 
 // Buffer -> C2Buffer
 // Note: The native handles will be cloned.
-c2_status_t objcpy(std::shared_ptr<C2Buffer>* d, const Buffer& s,
+bool objcpy(std::shared_ptr<C2Buffer>* d, const Buffer& s,
         const std::vector<C2BaseBlock>& baseBlocks) {
-    c2_status_t status;
     *d = nullptr;
 
     // Currently, a non-null C2Buffer must contain exactly 1 block.
     if (s.blocks.size() == 0) {
-        return C2_OK;
+        return true;
     } else if (s.blocks.size() != 1) {
-        ALOGE("Currently, a C2Buffer must contain exactly 1 block.");
-        return C2_BAD_VALUE;
+        LOG(ERROR) << "Invalid Buffer: "
+                      "Currently, a C2Buffer must contain exactly 1 block.";
+        return false;
     }
 
     const Block &sBlock = s.blocks[0];
     if (sBlock.index >= baseBlocks.size()) {
-        ALOGE("Index into baseBlocks is out of range.");
-        return C2_BAD_VALUE;
+        LOG(ERROR) << "Invalid Buffer::blocks[0].index: "
+                      "Array index out of range.";
+        return false;
     }
     const C2BaseBlock &baseBlock = baseBlocks[sBlock.index];
 
     // Parse meta.
     std::vector<C2Param*> sBlockMeta;
-    status = parseParamsBlob(&sBlockMeta, sBlock.meta);
-    if (status != C2_OK) {
-        ALOGE("Invalid block params blob.");
-        return C2_BAD_VALUE;
+    if (!parseParamsBlob(&sBlockMeta, sBlock.meta)) {
+        LOG(ERROR) << "Invalid Buffer::blocks[0].meta.";
+        return false;
     }
 
     // Copy fence.
     C2Fence dFence;
-    status = objcpy(&dFence, sBlock.fence);
+    if (!objcpy(&dFence, sBlock.fence)) {
+        LOG(ERROR) << "Invalid Buffer::blocks[0].fence.";
+        return false;
+    }
 
     // Construct a block.
     switch (baseBlock.type) {
     case C2BaseBlock::LINEAR:
-        status = createLinearBuffer(d, baseBlock.linear, sBlockMeta, dFence);
+        if (!createLinearBuffer(d, baseBlock.linear, sBlockMeta, dFence)) {
+            LOG(ERROR) << "Invalid C2BaseBlock::linear.";
+            return false;
+        }
         break;
     case C2BaseBlock::GRAPHIC:
-        status = createGraphicBuffer(d, baseBlock.graphic, sBlockMeta, dFence);
+        if (!createGraphicBuffer(d, baseBlock.graphic, sBlockMeta, dFence)) {
+            LOG(ERROR) << "Invalid C2BaseBlock::graphic.";
+            return false;
+        }
         break;
     default:
-        ALOGE("Invalid BaseBlock type.");
-        return C2_BAD_VALUE;
-    }
-    if (status != C2_OK) {
-        return status;
+        LOG(ERROR) << "Invalid C2BaseBlock::type.";
+        return false;
     }
 
     // Parse info
     std::vector<C2Param*> params;
-    status = parseParamsBlob(&params, s.info);
-    if (status != C2_OK) {
-        ALOGE("Invalid buffer params blob.");
-        return status;
+    if (!parseParamsBlob(&params, s.info)) {
+        LOG(ERROR) << "Invalid Buffer::info.";
+        return false;
     }
     for (C2Param* param : params) {
         if (param == nullptr) {
-            ALOGE("Null buffer param encountered.");
-            return C2_BAD_VALUE;
+            LOG(ERROR) << "Null param in Buffer::info.";
+            return false;
         }
-        std::shared_ptr<C2Param> c2param(
-                C2Param::Copy(*param).release());
+        std::shared_ptr<C2Param> c2param{
+                C2Param::Copy(*param).release()};
         if (!c2param) {
-            ALOGE("Invalid buffer param inside a blob.");
-            return C2_BAD_VALUE;
+            LOG(ERROR) << "Invalid param in Buffer::info.";
+            return false;
         }
-        status = (*d)->setInfo(std::static_pointer_cast<C2Info>(c2param));
+        c2_status_t status =
+                (*d)->setInfo(std::static_pointer_cast<C2Info>(c2param));
         if (status != C2_OK) {
-            ALOGE("C2Buffer::setInfo failed().");
-            return C2_BAD_VALUE;
+            LOG(ERROR) << "C2Buffer::setInfo failed.";
+            return false;
         }
     }
 
-    return C2_OK;
+    return true;
 }
 
 // FrameData -> C2FrameData
-c2_status_t objcpy(C2FrameData* d, const FrameData& s,
+bool objcpy(C2FrameData* d, const FrameData& s,
         const std::vector<C2BaseBlock>& baseBlocks) {
-    c2_status_t status;
     d->flags = static_cast<C2FrameData::flags_t>(s.flags);
-    objcpy(&d->ordinal, s.ordinal);
+    if (!objcpy(&d->ordinal, s.ordinal)) {
+        LOG(ERROR) << "Invalid FrameData::ordinal.";
+        return false;
+    }
     d->buffers.clear();
     d->buffers.reserve(s.buffers.size());
     for (const Buffer& sBuffer : s.buffers) {
         std::shared_ptr<C2Buffer> dBuffer;
-        status = objcpy(&dBuffer, sBuffer, baseBlocks);
-        if (status != C2_OK) {
-            return status;
+        if (!objcpy(&dBuffer, sBuffer, baseBlocks)) {
+            LOG(ERROR) << "Invalid FrameData::buffers.";
+            return false;
         }
         d->buffers.emplace_back(dBuffer);
     }
 
     std::vector<C2Param*> params;
-    status = parseParamsBlob(&params, s.configUpdate);
-    if (status != C2_OK) {
-        ALOGE("Failed to parse frame data params.");
-        return status;
+    if (!parseParamsBlob(&params, s.configUpdate)) {
+        LOG(ERROR) << "Invalid FrameData::configUpdate.";
+        return false;
     }
     d->configUpdate.clear();
     for (C2Param* param : params) {
         d->configUpdate.emplace_back(C2Param::Copy(*param));
         if (!d->configUpdate.back()) {
-            ALOGE("Unexpected error while parsing frame data params.");
-            return C2_BAD_VALUE;
+            LOG(ERROR) << "Unexpected error while parsing "
+                          "FrameData::configUpdate.";
+            return false;
         }
     }
 
     // TODO: Implement this once C2InfoBuffer has constructors.
     d->infoBuffers.clear();
-    return C2_OK;
+    return true;
 }
 
 // BaseBlock -> C2BaseBlock
-c2_status_t objcpy(C2BaseBlock* d, const BaseBlock& s) {
-    switch (s.type) {
-    case BaseBlock::Type::NATIVE: {
+bool objcpy(C2BaseBlock* d, const BaseBlock& s) {
+    switch (s.getDiscriminator()) {
+    case BaseBlock::hidl_discriminator::nativeBlock: {
             native_handle_t* sHandle =
-                    native_handle_clone(s.nativeBlock);
+                    native_handle_clone(s.nativeBlock());
             if (sHandle == nullptr) {
-                ALOGE("Null native handle in a block.");
-                return C2_BAD_VALUE;
+                LOG(ERROR) << "Null BaseBlock::nativeBlock.";
+                return false;
             }
             const C2Handle *sC2Handle =
                     reinterpret_cast<const C2Handle*>(sHandle);
@@ -1257,25 +1391,25 @@
             d->linear = _C2BlockFactory::CreateLinearBlock(sC2Handle);
             if (d->linear) {
                 d->type = C2BaseBlock::LINEAR;
-                return C2_OK;
+                return true;
             }
 
             d->graphic = _C2BlockFactory::CreateGraphicBlock(sC2Handle);
             if (d->graphic) {
                 d->type = C2BaseBlock::GRAPHIC;
-                return C2_OK;
+                return true;
             }
 
-            ALOGE("Unknown handle type in native BaseBlock.");
+            LOG(ERROR) << "Unknown handle type in BaseBlock::nativeBlock.";
             if (sHandle) {
                 native_handle_close(sHandle);
                 native_handle_delete(sHandle);
             }
-            return C2_BAD_VALUE;
+            return false;
         }
-    case BaseBlock::Type::POOLED: {
+    case BaseBlock::hidl_discriminator::pooledBlock: {
             const BufferStatusMessage &bpMessage =
-                    s.pooledBlock;
+                    s.pooledBlock();
             sp<ClientManager> bp = ClientManager::getInstance();
             std::shared_ptr<BufferPoolData> bpData;
             native_handle_t *cHandle;
@@ -1287,48 +1421,49 @@
                     &cHandle,
                     &bpData);
             if (bpStatus != ResultStatus::OK) {
-                ALOGE("Failed to receive buffer from bufferpool -- "
-                        "resultStatus = %d",
-                        static_cast<int>(bpStatus));
-                return toC2Status(bpStatus);
+                LOG(ERROR) << "Failed to receive buffer from bufferpool -- "
+                           << "resultStatus = " << underlying_value(bpStatus)
+                           << ".";
+                return false;
             } else if (!bpData) {
-                ALOGE("No data in bufferpool transaction.");
-                return C2_BAD_VALUE;
+                LOG(ERROR) << "No data in bufferpool transaction.";
+                return false;
             }
 
             d->linear = _C2BlockFactory::CreateLinearBlock(cHandle, bpData);
             if (d->linear) {
                 d->type = C2BaseBlock::LINEAR;
-                return C2_OK;
+                return true;
             }
 
             d->graphic = _C2BlockFactory::CreateGraphicBlock(cHandle, bpData);
             if (d->graphic) {
                 d->type = C2BaseBlock::GRAPHIC;
-                return C2_OK;
+                return true;
             }
 
-            ALOGE("Unknown handle type in pooled BaseBlock.");
-            return C2_BAD_VALUE;
+            LOG(ERROR) << "Unknown handle type in BaseBlock::pooledBlock.";
+            return false;
         }
     default:
-        ALOGE("Corrupted BaseBlock type: %d", static_cast<int>(s.type));
-        return C2_BAD_VALUE;
+        LOG(ERROR) << "Unrecognized BaseBlock's discriminator with "
+                   << "underlying value "
+                   << underlying_value(s.getDiscriminator()) << ".";
+        return false;
     }
 }
 
 } // unnamed namespace
 
 // WorkBundle -> std::list<std::unique_ptr<C2Work>>
-c2_status_t objcpy(std::list<std::unique_ptr<C2Work>>* d, const WorkBundle& s) {
-    c2_status_t status;
-
+bool objcpy(std::list<std::unique_ptr<C2Work>>* d, const WorkBundle& s) {
     // Convert BaseBlocks to C2BaseBlocks.
     std::vector<C2BaseBlock> dBaseBlocks(s.baseBlocks.size());
     for (size_t i = 0; i < s.baseBlocks.size(); ++i) {
-        status = objcpy(&dBaseBlocks[i], s.baseBlocks[i]);
-        if (status != C2_OK) {
-            return status;
+        if (!objcpy(&dBaseBlocks[i], s.baseBlocks[i])) {
+            LOG(ERROR) << "Invalid WorkBundle::baseBlocks["
+                       << i << "].";
+            return false;
         }
     }
 
@@ -1337,74 +1472,58 @@
         d->emplace_back(std::make_unique<C2Work>());
         C2Work& dWork = *d->back();
 
+        // chain info is not in use currently.
+
         // input
-        status = objcpy(&dWork.input, sWork.input, dBaseBlocks);
-        if (status != C2_OK) {
-            ALOGE("Error constructing C2Work's input.");
-            return C2_BAD_VALUE;
+        if (!objcpy(&dWork.input, sWork.input, dBaseBlocks)) {
+            LOG(ERROR) << "Invalid Work::input.";
+            return false;
         }
 
         // worklet(s)
         dWork.worklets.clear();
-        // TODO: Currently, tunneling is not supported.
-        if (sWork.workletProcessed) {
-            dWork.workletsProcessed = 1;
-
-            const Worklet &sWorklet = sWork.worklet;
+        for (const Worklet& sWorklet : sWork.worklets) {
             std::unique_ptr<C2Worklet> dWorklet = std::make_unique<C2Worklet>();
 
+            // component id
+            dWorklet->component = static_cast<c2_node_id_t>(
+                    sWorklet.componentId);
+
             // tunings
-            dWorklet->tunings.clear();
-            dWorklet->tunings.reserve(sWorklet.tunings.size());
-            for (const Params& sTuning : sWorklet.tunings) {
-                std::vector<C2Param*> dParams;
-                status = parseParamsBlob(&dParams, sTuning);
-                if (status != C2_OK) {
-                    ALOGE("Failed to parse C2Tuning in C2Worklet.");
-                    return C2_BAD_VALUE;
-                }
-                for (C2Param* param : dParams) {
-                    std::unique_ptr<C2Param> dParam = C2Param::Copy(*param);
-                    if (!dParam) {
-                        ALOGE("Null C2Tuning encountered while "
-                                "parsing C2Worklet.");
-                        return C2_BAD_VALUE;
-                    }
-                    dWorklet->tunings.emplace_back(
-                            std::unique_ptr<C2Tuning>(
-                            reinterpret_cast<C2Tuning*>(
-                            dParam.release())));
-                }
+            if (!copyParamsFromBlob(&dWorklet->tunings, sWorklet.tunings)) {
+                LOG(ERROR) << "Invalid Worklet::tunings";
+                return false;
             }
+
             // failures
             dWorklet->failures.clear();
             dWorklet->failures.reserve(sWorklet.failures.size());
             for (const SettingResult& sFailure : sWorklet.failures) {
                 std::unique_ptr<C2SettingResult> dFailure;
-                status = objcpy(&dFailure, sFailure);
-                if (status != C2_OK) {
-                    ALOGE("Failed to create C2SettingResult in C2Worklet.");
-                    return C2_BAD_VALUE;
+                if (!objcpy(&dFailure, sFailure)) {
+                    LOG(ERROR) << "Invalid Worklet::failures.";
+                    return false;
                 }
                 dWorklet->failures.emplace_back(std::move(dFailure));
             }
+
             // output
-            status = objcpy(&dWorklet->output, sWorklet.output, dBaseBlocks);
-            if (status != C2_OK) {
-                ALOGE("Failed to create output C2FrameData.");
-                return C2_BAD_VALUE;
+            if (!objcpy(&dWorklet->output, sWorklet.output, dBaseBlocks)) {
+                LOG(ERROR) << "Invalid Worklet::output.";
+                return false;
             }
+
             dWork.worklets.emplace_back(std::move(dWorklet));
-        } else {
-            dWork.worklets.emplace_back(std::make_unique<C2Worklet>());
-            dWork.workletsProcessed = 0;
         }
 
+        // workletsProcessed
+        dWork.workletsProcessed = sWork.workletsProcessed;
+
         // result
         dWork.result = static_cast<c2_status_t>(sWork.result);
     }
 
-    return C2_OK;
+    return true;
 }
 
 constexpr size_t PARAMS_ALIGNMENT = 8;  // 64-bit alignment
@@ -1413,7 +1532,7 @@
 static_assert(PARAMS_ALIGNMENT % alignof(C2Tuning) == 0, "C2Param alignment mismatch");
 
 // Params -> std::vector<C2Param*>
-c2_status_t parseParamsBlob(std::vector<C2Param*> *params, const hidl_vec<uint8_t> &blob) {
+bool parseParamsBlob(std::vector<C2Param*> *params, const hidl_vec<uint8_t> &blob) {
     // assuming blob is const here
     size_t size = blob.size();
     size_t ix = 0;
@@ -1429,21 +1548,27 @@
         }
     } while (p);
 
-    return ix == size ? C2_OK : C2_BAD_VALUE;
+    if (ix != size) {
+        LOG(ERROR) << "parseParamsBlob -- inconsistent sizes.";
+        return false;
+    }
+    return true;
 }
 
 namespace /* unnamed */ {
 
 /**
- * Concatenates a list of C2Params into a params blob.
+ * Concatenates a list of C2Params into a params blob. T is a container type
+ * whose member type is compatible with C2Param*.
+ *
  * \param[out] blob target blob
  * \param[in] params parameters to concatenate
  * \retval C2_OK if the blob was successfully created
- * \retval C2_BAD_VALUE if the blob was not successful (this only happens if the parameters were
- *         not const)
+ * \retval C2_BAD_VALUE if the blob was not successful created (this only
+ *         happens if the parameters were not const)
  */
-template<typename T>
-Status _createParamsBlob(hidl_vec<uint8_t> *blob, const T &params) {
+template <typename T>
+bool _createParamsBlob(hidl_vec<uint8_t> *blob, const T &params) {
     // assuming the parameter values are const
     size_t size = 0;
     for (const auto &p : params) {
@@ -1469,77 +1594,106 @@
         ix = align(ix, PARAMS_ALIGNMENT);
     }
     blob->resize(ix);
-    return ix == size ? Status::OK : Status::CORRUPTED;
+    if (ix != size) {
+        LOG(ERROR) << "createParamsBlob -- inconsistent sizes.";
+        return false;
+    }
+    return true;
+}
+
+/**
+ * Parses a params blob and create a vector of new T objects that contain copies
+ * of the params in the blob. T is C2Param or its compatible derived class.
+ *
+ * \param[out] params the resulting vector
+ * \param[in] blob parameter blob to parse
+ * \retval C2_OK if the full blob was parsed and params was constructed
+ * \retval C2_BAD_VALUE otherwise
+ */
+template <typename T>
+bool _copyParamsFromBlob(
+        std::vector<std::unique_ptr<T>>* params,
+        Params blob) {
+
+    std::vector<C2Param*> paramPointers;
+    if (!parseParamsBlob(&paramPointers, blob)) {
+        LOG(ERROR) << "copyParamsFromBlob -- failed to parse.";
+        return false;
+    }
+
+    params->resize(paramPointers.size());
+    size_t i = 0;
+    for (C2Param* const& paramPointer : paramPointers) {
+        if (!paramPointer) {
+            LOG(ERROR) << "copyParamsFromBlob -- null paramPointer.";
+            return false;
+        }
+        (*params)[i++].reset(reinterpret_cast<T*>(
+                C2Param::Copy(*paramPointer).release()));
+    }
+    return true;
 }
 
 } // unnamed namespace
 
 // std::vector<const C2Param*> -> Params
-Status createParamsBlob(
+bool createParamsBlob(
         hidl_vec<uint8_t> *blob,
         const std::vector<const C2Param*> &params) {
     return _createParamsBlob(blob, params);
 }
 
 // std::vector<C2Param*> -> Params
-Status createParamsBlob(
+bool createParamsBlob(
         hidl_vec<uint8_t> *blob,
         const std::vector<C2Param*> &params) {
     return _createParamsBlob(blob, params);
 }
 
 // std::vector<std::unique_ptr<C2Param>> -> Params
-Status createParamsBlob(
+bool createParamsBlob(
         hidl_vec<uint8_t> *blob,
         const std::vector<std::unique_ptr<C2Param>> &params) {
     return _createParamsBlob(blob, params);
 }
 
 // std::vector<std::unique_ptr<C2Tuning>> -> Params
-Status createParamsBlob(
+bool createParamsBlob(
         hidl_vec<uint8_t> *blob,
         const std::vector<std::unique_ptr<C2Tuning>> &params) {
     return _createParamsBlob(blob, params);
 }
 
 // std::vector<std::shared_ptr<const C2Info>> -> Params
-Status createParamsBlob(
+bool createParamsBlob(
         hidl_vec<uint8_t> *blob,
         const std::vector<std::shared_ptr<const C2Info>> &params) {
     return _createParamsBlob(blob, params);
 }
 
 // Params -> std::vector<std::unique_ptr<C2Param>>
-c2_status_t copyParamsFromBlob(
+bool copyParamsFromBlob(
         std::vector<std::unique_ptr<C2Param>>* params,
         Params blob) {
-    std::vector<C2Param*> paramPointers;
-    c2_status_t status = parseParamsBlob(&paramPointers, blob);
-    if (status != C2_OK) {
-        ALOGE("copyParamsFromBlob -- blob parsing failed.");
-        return status;
-    }
-    params->resize(paramPointers.size());
-    size_t i = 0;
-    for (C2Param* const& paramPointer : paramPointers) {
-        if (!paramPointer) {
-            ALOGE("copyParamsFromBlob -- corrupted params blob.");
-            return C2_BAD_VALUE;
-        }
-        (*params)[i++] = C2Param::Copy(*paramPointer);
-    }
-    return C2_OK;
+    return _copyParamsFromBlob(params, blob);
+}
+
+// Params -> std::vector<std::unique_ptr<C2Tuning>>
+bool copyParamsFromBlob(
+        std::vector<std::unique_ptr<C2Tuning>>* params,
+        Params blob) {
+    return _copyParamsFromBlob(params, blob);
 }
 
 // Params -> update std::vector<std::unique_ptr<C2Param>>
-c2_status_t updateParamsFromBlob(
+bool updateParamsFromBlob(
         const std::vector<C2Param*>& params,
         const Params& blob) {
     std::unordered_map<uint32_t, C2Param*> index2param;
     for (C2Param* const& param : params) {
         if (!param) {
-            ALOGE("updateParamsFromBlob -- corrupted input params.");
-            return C2_BAD_VALUE;
+            LOG(ERROR) << "updateParamsFromBlob -- null output param.";
+            return false;
         }
         if (index2param.find(param->index()) == index2param.end()) {
             index2param.emplace(param->index(), param);
@@ -1547,33 +1701,31 @@
     }
 
     std::vector<C2Param*> paramPointers;
-    c2_status_t status = parseParamsBlob(&paramPointers, blob);
-    if (status != C2_OK) {
-        ALOGE("updateParamsFromBlob -- blob parsing failed.");
-        return status;
+    if (!parseParamsBlob(&paramPointers, blob)) {
+        LOG(ERROR) << "updateParamsFromBlob -- failed to parse.";
+        return false;
     }
 
     for (C2Param* const& paramPointer : paramPointers) {
         if (!paramPointer) {
-            ALOGE("updateParamsFromBlob -- corrupted param in blob.");
-            return C2_BAD_VALUE;
+            LOG(ERROR) << "updateParamsFromBlob -- null input param.";
+            return false;
         }
         decltype(index2param)::iterator i = index2param.find(
                 paramPointer->index());
         if (i == index2param.end()) {
-            ALOGW("updateParamsFromBlob -- unseen param index.");
+            LOG(DEBUG) << "updateParamsFromBlob -- index "
+                       << paramPointer->index() << " not found. Skipping...";
             continue;
         }
         if (!i->second->updateFrom(*paramPointer)) {
-            ALOGE("updateParamsFromBlob -- mismatching sizes: "
-                    "%u vs %u (index = %u).",
-                    static_cast<unsigned>(params.size()),
-                    static_cast<unsigned>(paramPointer->size()),
-                    static_cast<unsigned>(i->first));
-            return C2_BAD_VALUE;
+            LOG(ERROR) << "updateParamsFromBlob -- size mismatch: "
+                       << params.size() << " vs " << paramPointer->size()
+                       << " (index = " << i->first << ").";
+            return false;
         }
     }
-    return C2_OK;
+    return true;
 }
 
 // Convert BufferPool ResultStatus to c2_status_t.
@@ -1590,7 +1742,8 @@
     case ResultStatus::CRITICAL_ERROR:
         return C2_CORRUPTED;
     default:
-        ALOGW("Unrecognized BufferPool ResultStatus: %d", static_cast<int>(rs));
+        LOG(WARNING) << "Unrecognized BufferPool ResultStatus: "
+                     << static_cast<int32_t>(rs) << ".";
         return C2_CORRUPTED;
     }
 }
@@ -1669,34 +1822,33 @@
                              uint32_t generation,
                              int32_t* bqSlot) {
     if (!igbp) {
-        ALOGW("attachToBufferQueue -- null producer.");
+        LOG(WARNING) << "attachToBufferQueue -- null producer.";
         return NO_INIT;
     }
 
     sp<GraphicBuffer> graphicBuffer = createGraphicBuffer(block);
     graphicBuffer->setGenerationNumber(generation);
 
-    ALOGV("attachToBufferQueue -- attaching buffer: "
-            "block dimension %ux%u, "
-            "graphicBuffer dimension %ux%u, "
-            "format %#x, usage %#llx, stride %u, generation %u.",
-            static_cast<unsigned>(block.width()),
-            static_cast<unsigned>(block.height()),
-            static_cast<unsigned>(graphicBuffer->getWidth()),
-            static_cast<unsigned>(graphicBuffer->getHeight()),
-            static_cast<unsigned>(graphicBuffer->getPixelFormat()),
-            static_cast<unsigned long long>(graphicBuffer->getUsage()),
-            static_cast<unsigned>(graphicBuffer->getStride()),
-            static_cast<unsigned>(graphicBuffer->getGenerationNumber()));
+    LOG(VERBOSE) << "attachToBufferQueue -- attaching buffer:"
+            << " block dimension " << block.width() << "x"
+                                   << block.height()
+            << ", graphicBuffer dimension " << graphicBuffer->getWidth() << "x"
+                                           << graphicBuffer->getHeight()
+            << std::hex << std::setfill('0')
+            << ", format 0x" << std::setw(8) << graphicBuffer->getPixelFormat()
+            << ", usage 0x" << std::setw(16) << graphicBuffer->getUsage()
+            << std::dec << std::setfill(' ')
+            << ", stride " << graphicBuffer->getStride()
+            << ", generation " << graphicBuffer->getGenerationNumber();
 
     status_t result = igbp->attachBuffer(bqSlot, graphicBuffer);
     if (result != OK) {
-        ALOGW("attachToBufferQueue -- attachBuffer failed. Error code = %d",
-                static_cast<int>(result));
+        LOG(WARNING) << "attachToBufferQueue -- attachBuffer failed: "
+                        "status = " << result << ".";
         return result;
     }
-    ALOGV("attachToBufferQueue -- attachBuffer returned slot %d",
-            static_cast<int>(*bqSlot));
+    LOG(VERBOSE) << "attachToBufferQueue -- attachBuffer returned slot #"
+                 << *bqSlot << ".";
     return OK;
 }
 
@@ -1747,11 +1899,11 @@
 
     // If the block's bqId is the same as the desired bqId, just hold.
     if ((oldId == bqId) && (oldGeneration == generation)) {
-        ALOGV("holdBufferQueueBlock -- import without attaching: "
-                "bqId %llu, bqSlot %d, generation %u.",
-                static_cast<long long unsigned>(oldId),
-                static_cast<int>(oldSlot),
-                static_cast<unsigned>(generation));
+        LOG(VERBOSE) << "holdBufferQueueBlock -- import without attaching:"
+                     << " bqId " << oldId
+                     << ", bqSlot " << oldSlot
+                     << ", generation " << generation
+                     << ".";
         _C2BlockFactory::HoldBlockFromBufferQueue(data, getHgbp(igbp));
         return true;
     }
@@ -1765,19 +1917,18 @@
     status_t result = attachToBufferQueue(block, igbp, generation, &bqSlot);
 
     if (result != OK) {
-        ALOGE("holdBufferQueueBlock -- fail to attach: "
-                "target bqId %llu, generation %u.",
-                static_cast<long long unsigned>(bqId),
-                static_cast<unsigned>(generation));
-
+        LOG(ERROR) << "holdBufferQueueBlock -- fail to attach:"
+                   << " target bqId " << bqId
+                   << ", generation " << generation
+                   << ".";
         return false;
     }
 
-    ALOGV("holdBufferQueueBlock -- attached: "
-            "bqId %llu, bqSlot %d, generation %u.",
-            static_cast<long long unsigned>(bqId),
-            static_cast<int>(bqSlot),
-            static_cast<unsigned>(generation));
+    LOG(VERBOSE) << "holdBufferQueueBlock -- attached:"
+                 << " bqId " << bqId
+                 << ", bqSlot " << bqSlot
+                 << ", generation " << generation
+                 << ".";
     _C2BlockFactory::AssignBlockToBufferQueue(
             data, getHgbp(igbp), generation, bqId, bqSlot, true);
     return true;
diff --git a/media/codec2/hidl/1.0/vts/OWNERS b/media/codec2/hidl/1.0/vts/OWNERS
new file mode 100644
index 0000000..6733e0c
--- /dev/null
+++ b/media/codec2/hidl/1.0/vts/OWNERS
@@ -0,0 +1,9 @@
+# Media team
+lajos@google.com
+pawin@google.com
+taklee@google.com
+wonsik@google.com
+
+# VTS team
+yim@google.com
+zhuoyao@google.com
diff --git a/media/codec2/hidl/1.0/vts/audio/Android.bp b/media/codec2/hidl/1.0/vts/functional/audio/Android.bp
similarity index 100%
rename from media/codec2/hidl/1.0/vts/audio/Android.bp
rename to media/codec2/hidl/1.0/vts/functional/audio/Android.bp
diff --git a/media/codec2/hidl/1.0/vts/audio/VtsHidlC2V1_0TargetAudioDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioDecTest.cpp
similarity index 100%
rename from media/codec2/hidl/1.0/vts/audio/VtsHidlC2V1_0TargetAudioDecTest.cpp
rename to media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioDecTest.cpp
diff --git a/media/codec2/hidl/1.0/vts/audio/VtsHidlC2V1_0TargetAudioEncTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioEncTest.cpp
similarity index 100%
rename from media/codec2/hidl/1.0/vts/audio/VtsHidlC2V1_0TargetAudioEncTest.cpp
rename to media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioEncTest.cpp
diff --git a/media/codec2/hidl/1.0/vts/audio/media_c2_audio_hidl_test_common.h b/media/codec2/hidl/1.0/vts/functional/audio/media_c2_audio_hidl_test_common.h
similarity index 100%
rename from media/codec2/hidl/1.0/vts/audio/media_c2_audio_hidl_test_common.h
rename to media/codec2/hidl/1.0/vts/functional/audio/media_c2_audio_hidl_test_common.h
diff --git a/media/codec2/hidl/1.0/vts/common/Android.bp b/media/codec2/hidl/1.0/vts/functional/common/Android.bp
similarity index 100%
rename from media/codec2/hidl/1.0/vts/common/Android.bp
rename to media/codec2/hidl/1.0/vts/functional/common/Android.bp
diff --git a/media/codec2/hidl/1.0/vts/common/README.md b/media/codec2/hidl/1.0/vts/functional/common/README.md
similarity index 100%
rename from media/codec2/hidl/1.0/vts/common/README.md
rename to media/codec2/hidl/1.0/vts/functional/common/README.md
diff --git a/media/codec2/hidl/1.0/vts/common/media_c2_hidl_test_common.cpp b/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
similarity index 100%
rename from media/codec2/hidl/1.0/vts/common/media_c2_hidl_test_common.cpp
rename to media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
diff --git a/media/codec2/hidl/1.0/vts/common/media_c2_hidl_test_common.h b/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h
similarity index 96%
rename from media/codec2/hidl/1.0/vts/common/media_c2_hidl_test_common.h
rename to media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h
index a688530..d1557cb 100644
--- a/media/codec2/hidl/1.0/vts/common/media_c2_hidl_test_common.h
+++ b/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h
@@ -94,10 +94,14 @@
         (void)buffer;
     }
 
-    virtual void onFramesRendered(
-        const std::vector<RenderedFrame>& renderedFrames) override {
+    virtual void onFrameRendered(
+        uint64_t bufferQueueId,
+        int32_t slotId,
+        int64_t timestampNs) override {
         /* TODO */
-        (void)renderedFrames;
+        (void)bufferQueueId;
+        (void)slotId;
+        (void)timestampNs;
     }
     // std::mutex mQueueLock;
     // std::condition_variable mQueueCondition;
diff --git a/media/codec2/hidl/1.0/vts/component/Android.bp b/media/codec2/hidl/1.0/vts/functional/component/Android.bp
similarity index 100%
rename from media/codec2/hidl/1.0/vts/component/Android.bp
rename to media/codec2/hidl/1.0/vts/functional/component/Android.bp
diff --git a/media/codec2/hidl/1.0/vts/component/VtsHidlC2V1_0TargetComponentTest.cpp b/media/codec2/hidl/1.0/vts/functional/component/VtsHidlC2V1_0TargetComponentTest.cpp
similarity index 100%
rename from media/codec2/hidl/1.0/vts/component/VtsHidlC2V1_0TargetComponentTest.cpp
rename to media/codec2/hidl/1.0/vts/functional/component/VtsHidlC2V1_0TargetComponentTest.cpp
diff --git a/media/codec2/hidl/1.0/vts/master/Android.bp b/media/codec2/hidl/1.0/vts/functional/master/Android.bp
similarity index 100%
rename from media/codec2/hidl/1.0/vts/master/Android.bp
rename to media/codec2/hidl/1.0/vts/functional/master/Android.bp
diff --git a/media/codec2/hidl/1.0/vts/master/VtsHidlC2V1_0TargetMasterTest.cpp b/media/codec2/hidl/1.0/vts/functional/master/VtsHidlC2V1_0TargetMasterTest.cpp
similarity index 100%
rename from media/codec2/hidl/1.0/vts/master/VtsHidlC2V1_0TargetMasterTest.cpp
rename to media/codec2/hidl/1.0/vts/functional/master/VtsHidlC2V1_0TargetMasterTest.cpp
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_352x288_420p_30fps_32frames.yuv b/media/codec2/hidl/1.0/vts/functional/res/bbb_352x288_420p_30fps_32frames.yuv
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_352x288_420p_30fps_32frames.yuv
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_352x288_420p_30fps_32frames.yuv
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_aac_stereo_128kbps_48000hz.aac b/media/codec2/hidl/1.0/vts/functional/res/bbb_aac_stereo_128kbps_48000hz.aac
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_aac_stereo_128kbps_48000hz.aac
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_aac_stereo_128kbps_48000hz.aac
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_aac_stereo_128kbps_48000hz.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_aac_stereo_128kbps_48000hz.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_aac_stereo_128kbps_48000hz.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_aac_stereo_128kbps_48000hz.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_aac_stereo_128kbps_48000hz_multi_frame.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_aac_stereo_128kbps_48000hz_multi_frame.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_aac_stereo_128kbps_48000hz_multi_frame.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_aac_stereo_128kbps_48000hz_multi_frame.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_amrwb_1ch_14kbps_16000hz.amrwb b/media/codec2/hidl/1.0/vts/functional/res/bbb_amrwb_1ch_14kbps_16000hz.amrwb
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_amrwb_1ch_14kbps_16000hz.amrwb
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_amrwb_1ch_14kbps_16000hz.amrwb
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_amrwb_1ch_14kbps_16000hz.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_amrwb_1ch_14kbps_16000hz.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_amrwb_1ch_14kbps_16000hz.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_amrwb_1ch_14kbps_16000hz.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_amrwb_1ch_14kbps_16000hz_multi_frame.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_amrwb_1ch_14kbps_16000hz_multi_frame.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_amrwb_1ch_14kbps_16000hz_multi_frame.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_amrwb_1ch_14kbps_16000hz_multi_frame.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_av1_176_144.av1 b/media/codec2/hidl/1.0/vts/functional/res/bbb_av1_176_144.av1
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_av1_176_144.av1
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_av1_176_144.av1
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_av1_176_144.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_av1_176_144.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_av1_176_144.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_av1_176_144.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_av1_640_360.av1 b/media/codec2/hidl/1.0/vts/functional/res/bbb_av1_640_360.av1
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_av1_640_360.av1
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_av1_640_360.av1
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_av1_640_360.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_av1_640_360.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_av1_640_360.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_av1_640_360.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_avc_176x144_300kbps_60fps.h264 b/media/codec2/hidl/1.0/vts/functional/res/bbb_avc_176x144_300kbps_60fps.h264
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_avc_176x144_300kbps_60fps.h264
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_avc_176x144_300kbps_60fps.h264
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_avc_176x144_300kbps_60fps.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_avc_176x144_300kbps_60fps.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_avc_176x144_300kbps_60fps.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_avc_176x144_300kbps_60fps.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_avc_640x360_768kbps_30fps.h264 b/media/codec2/hidl/1.0/vts/functional/res/bbb_avc_640x360_768kbps_30fps.h264
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_avc_640x360_768kbps_30fps.h264
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_avc_640x360_768kbps_30fps.h264
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_avc_640x360_768kbps_30fps.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_avc_640x360_768kbps_30fps.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_avc_640x360_768kbps_30fps.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_avc_640x360_768kbps_30fps.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_flac_stereo_680kbps_48000hz.flac b/media/codec2/hidl/1.0/vts/functional/res/bbb_flac_stereo_680kbps_48000hz.flac
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_flac_stereo_680kbps_48000hz.flac
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_flac_stereo_680kbps_48000hz.flac
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_flac_stereo_680kbps_48000hz.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_flac_stereo_680kbps_48000hz.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_flac_stereo_680kbps_48000hz.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_flac_stereo_680kbps_48000hz.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_g711alaw_1ch_8khz.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_g711alaw_1ch_8khz.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_g711alaw_1ch_8khz.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_g711alaw_1ch_8khz.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_g711alaw_1ch_8khz.raw b/media/codec2/hidl/1.0/vts/functional/res/bbb_g711alaw_1ch_8khz.raw
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_g711alaw_1ch_8khz.raw
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_g711alaw_1ch_8khz.raw
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_g711mulaw_1ch_8khz.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_g711mulaw_1ch_8khz.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_g711mulaw_1ch_8khz.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_g711mulaw_1ch_8khz.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_g711mulaw_1ch_8khz.raw b/media/codec2/hidl/1.0/vts/functional/res/bbb_g711mulaw_1ch_8khz.raw
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_g711mulaw_1ch_8khz.raw
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_g711mulaw_1ch_8khz.raw
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_gsm_1ch_8khz_13kbps.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_gsm_1ch_8khz_13kbps.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_gsm_1ch_8khz_13kbps.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_gsm_1ch_8khz_13kbps.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_gsm_1ch_8khz_13kbps.raw b/media/codec2/hidl/1.0/vts/functional/res/bbb_gsm_1ch_8khz_13kbps.raw
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_gsm_1ch_8khz_13kbps.raw
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_gsm_1ch_8khz_13kbps.raw
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_h263_352x288_300kbps_12fps.h263 b/media/codec2/hidl/1.0/vts/functional/res/bbb_h263_352x288_300kbps_12fps.h263
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_h263_352x288_300kbps_12fps.h263
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_h263_352x288_300kbps_12fps.h263
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_h263_352x288_300kbps_12fps.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_h263_352x288_300kbps_12fps.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_h263_352x288_300kbps_12fps.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_h263_352x288_300kbps_12fps.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_hevc_176x144_176kbps_60fps.hevc b/media/codec2/hidl/1.0/vts/functional/res/bbb_hevc_176x144_176kbps_60fps.hevc
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_hevc_176x144_176kbps_60fps.hevc
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_hevc_176x144_176kbps_60fps.hevc
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_hevc_176x144_176kbps_60fps.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_hevc_176x144_176kbps_60fps.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_hevc_176x144_176kbps_60fps.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_hevc_176x144_176kbps_60fps.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_hevc_640x360_1600kbps_30fps.hevc b/media/codec2/hidl/1.0/vts/functional/res/bbb_hevc_640x360_1600kbps_30fps.hevc
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_hevc_640x360_1600kbps_30fps.hevc
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_hevc_640x360_1600kbps_30fps.hevc
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_hevc_640x360_1600kbps_30fps.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_hevc_640x360_1600kbps_30fps.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_hevc_640x360_1600kbps_30fps.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_hevc_640x360_1600kbps_30fps.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_mp3_stereo_192kbps_48000hz.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_mp3_stereo_192kbps_48000hz.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_mp3_stereo_192kbps_48000hz.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_mp3_stereo_192kbps_48000hz.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_mp3_stereo_192kbps_48000hz.mp3 b/media/codec2/hidl/1.0/vts/functional/res/bbb_mp3_stereo_192kbps_48000hz.mp3
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_mp3_stereo_192kbps_48000hz.mp3
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_mp3_stereo_192kbps_48000hz.mp3
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_mp3_stereo_192kbps_48000hz_multi_frame.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_mp3_stereo_192kbps_48000hz_multi_frame.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_mp3_stereo_192kbps_48000hz_multi_frame.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_mp3_stereo_192kbps_48000hz_multi_frame.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_mpeg2_176x144_105kbps_25fps.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_mpeg2_176x144_105kbps_25fps.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_mpeg2_176x144_105kbps_25fps.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_mpeg2_176x144_105kbps_25fps.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_mpeg2_176x144_105kbps_25fps.m2v b/media/codec2/hidl/1.0/vts/functional/res/bbb_mpeg2_176x144_105kbps_25fps.m2v
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_mpeg2_176x144_105kbps_25fps.m2v
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_mpeg2_176x144_105kbps_25fps.m2v
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_mpeg2_352x288_1mbps_60fps.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_mpeg2_352x288_1mbps_60fps.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_mpeg2_352x288_1mbps_60fps.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_mpeg2_352x288_1mbps_60fps.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_mpeg2_352x288_1mbps_60fps.m2v b/media/codec2/hidl/1.0/vts/functional/res/bbb_mpeg2_352x288_1mbps_60fps.m2v
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_mpeg2_352x288_1mbps_60fps.m2v
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_mpeg2_352x288_1mbps_60fps.m2v
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_mpeg4_352x288_512kbps_30fps.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_mpeg4_352x288_512kbps_30fps.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_mpeg4_352x288_512kbps_30fps.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_mpeg4_352x288_512kbps_30fps.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_mpeg4_352x288_512kbps_30fps.m4v b/media/codec2/hidl/1.0/vts/functional/res/bbb_mpeg4_352x288_512kbps_30fps.m4v
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_mpeg4_352x288_512kbps_30fps.m4v
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_mpeg4_352x288_512kbps_30fps.m4v
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_opus_stereo_128kbps_48000hz.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_opus_stereo_128kbps_48000hz.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_opus_stereo_128kbps_48000hz.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_opus_stereo_128kbps_48000hz.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_opus_stereo_128kbps_48000hz.opus b/media/codec2/hidl/1.0/vts/functional/res/bbb_opus_stereo_128kbps_48000hz.opus
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_opus_stereo_128kbps_48000hz.opus
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_opus_stereo_128kbps_48000hz.opus
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_raw_1ch_16khz_s16le.raw b/media/codec2/hidl/1.0/vts/functional/res/bbb_raw_1ch_16khz_s16le.raw
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_raw_1ch_16khz_s16le.raw
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_raw_1ch_16khz_s16le.raw
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_raw_1ch_8khz_s16le.raw b/media/codec2/hidl/1.0/vts/functional/res/bbb_raw_1ch_8khz_s16le.raw
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_raw_1ch_8khz_s16le.raw
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_raw_1ch_8khz_s16le.raw
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_raw_1ch_8khz_s32le.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_raw_1ch_8khz_s32le.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_raw_1ch_8khz_s32le.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_raw_1ch_8khz_s32le.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_raw_1ch_8khz_s32le.raw b/media/codec2/hidl/1.0/vts/functional/res/bbb_raw_1ch_8khz_s32le.raw
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_raw_1ch_8khz_s32le.raw
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_raw_1ch_8khz_s32le.raw
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_raw_2ch_48khz_s16le.raw b/media/codec2/hidl/1.0/vts/functional/res/bbb_raw_2ch_48khz_s16le.raw
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_raw_2ch_48khz_s16le.raw
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_raw_2ch_48khz_s16le.raw
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_vorbis_stereo_128kbps_48000hz.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_vorbis_stereo_128kbps_48000hz.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_vorbis_stereo_128kbps_48000hz.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_vorbis_stereo_128kbps_48000hz.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_vorbis_stereo_128kbps_48000hz.vorbis b/media/codec2/hidl/1.0/vts/functional/res/bbb_vorbis_stereo_128kbps_48000hz.vorbis
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_vorbis_stereo_128kbps_48000hz.vorbis
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_vorbis_stereo_128kbps_48000hz.vorbis
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_vp8_176x144_240kbps_60fps.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_vp8_176x144_240kbps_60fps.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_vp8_176x144_240kbps_60fps.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_vp8_176x144_240kbps_60fps.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_vp8_176x144_240kbps_60fps.vp8 b/media/codec2/hidl/1.0/vts/functional/res/bbb_vp8_176x144_240kbps_60fps.vp8
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_vp8_176x144_240kbps_60fps.vp8
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_vp8_176x144_240kbps_60fps.vp8
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_vp8_640x360_2mbps_30fps.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_vp8_640x360_2mbps_30fps.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_vp8_640x360_2mbps_30fps.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_vp8_640x360_2mbps_30fps.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_vp8_640x360_2mbps_30fps.vp8 b/media/codec2/hidl/1.0/vts/functional/res/bbb_vp8_640x360_2mbps_30fps.vp8
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_vp8_640x360_2mbps_30fps.vp8
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_vp8_640x360_2mbps_30fps.vp8
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_vp9_176x144_285kbps_60fps.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_vp9_176x144_285kbps_60fps.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_vp9_176x144_285kbps_60fps.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_vp9_176x144_285kbps_60fps.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_vp9_176x144_285kbps_60fps.vp9 b/media/codec2/hidl/1.0/vts/functional/res/bbb_vp9_176x144_285kbps_60fps.vp9
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_vp9_176x144_285kbps_60fps.vp9
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_vp9_176x144_285kbps_60fps.vp9
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_vp9_640x360_1600kbps_30fps.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_vp9_640x360_1600kbps_30fps.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_vp9_640x360_1600kbps_30fps.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_vp9_640x360_1600kbps_30fps.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_vp9_640x360_1600kbps_30fps.vp9 b/media/codec2/hidl/1.0/vts/functional/res/bbb_vp9_640x360_1600kbps_30fps.vp9
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_vp9_640x360_1600kbps_30fps.vp9
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_vp9_640x360_1600kbps_30fps.vp9
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/sine_amrnb_1ch_12kbps_8000hz.amrnb b/media/codec2/hidl/1.0/vts/functional/res/sine_amrnb_1ch_12kbps_8000hz.amrnb
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/sine_amrnb_1ch_12kbps_8000hz.amrnb
rename to media/codec2/hidl/1.0/vts/functional/res/sine_amrnb_1ch_12kbps_8000hz.amrnb
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/sine_amrnb_1ch_12kbps_8000hz.info b/media/codec2/hidl/1.0/vts/functional/res/sine_amrnb_1ch_12kbps_8000hz.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/sine_amrnb_1ch_12kbps_8000hz.info
rename to media/codec2/hidl/1.0/vts/functional/res/sine_amrnb_1ch_12kbps_8000hz.info
diff --git a/media/codec2/hidl/1.0/vts/res/sine_amrnb_1ch_12kbps_8000hz_multi_frame.info b/media/codec2/hidl/1.0/vts/functional/res/sine_amrnb_1ch_12kbps_8000hz_multi_frame.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/sine_amrnb_1ch_12kbps_8000hz_multi_frame.info
rename to media/codec2/hidl/1.0/vts/functional/res/sine_amrnb_1ch_12kbps_8000hz_multi_frame.info
diff --git a/media/codec2/hidl/1.0/vts/video/Android.bp b/media/codec2/hidl/1.0/vts/functional/video/Android.bp
similarity index 100%
rename from media/codec2/hidl/1.0/vts/video/Android.bp
rename to media/codec2/hidl/1.0/vts/functional/video/Android.bp
diff --git a/media/codec2/hidl/1.0/vts/video/VtsHidlC2V1_0TargetVideoDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoDecTest.cpp
similarity index 100%
rename from media/codec2/hidl/1.0/vts/video/VtsHidlC2V1_0TargetVideoDecTest.cpp
rename to media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoDecTest.cpp
diff --git a/media/codec2/hidl/1.0/vts/video/VtsHidlC2V1_0TargetVideoEncTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoEncTest.cpp
similarity index 100%
rename from media/codec2/hidl/1.0/vts/video/VtsHidlC2V1_0TargetVideoEncTest.cpp
rename to media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoEncTest.cpp
diff --git a/media/codec2/hidl/1.0/vts/video/media_c2_video_hidl_test_common.h b/media/codec2/hidl/1.0/vts/functional/video/media_c2_video_hidl_test_common.h
similarity index 100%
rename from media/codec2/hidl/1.0/vts/video/media_c2_video_hidl_test_common.h
rename to media/codec2/hidl/1.0/vts/functional/video/media_c2_video_hidl_test_common.h
diff --git a/media/codec2/hidl/client/client.cpp b/media/codec2/hidl/client/client.cpp
index cd374b0..5b52fcd 100644
--- a/media/codec2/hidl/client/client.cpp
+++ b/media/codec2/hidl/client/client.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -16,7 +16,7 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "Codec2Client"
-#include <log/log.h>
+#include <android-base/logging.h>
 
 #include <codec2/hidl/client.h>
 
@@ -32,7 +32,6 @@
 #include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
 #include <hidl/HidlSupport.h>
 #include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
-#undef LOG
 
 #include <android/hardware/media/bufferpool/2.0/IClientManager.h>
 #include <android/hardware/media/c2/1.0/IComponent.h>
@@ -99,19 +98,17 @@
     return mName;
 }
 
-Codec2ConfigurableClient::Base* Codec2ConfigurableClient::base() const {
-    return static_cast<Base*>(mBase.get());
-}
-
 Codec2ConfigurableClient::Codec2ConfigurableClient(
-        const sp<Codec2ConfigurableClient::Base>& base) : mBase(base) {
-    Return<void> transStatus = base->getName(
-            [this](const hidl_string& name) {
-                mName = name.c_str();
-            });
-    if (!transStatus.isOk()) {
-        ALOGE("Cannot obtain name from IConfigurable.");
-    }
+        const sp<IConfigurable>& base)
+      : mBase{base},
+        mName{[base]() -> C2String {
+                C2String outName;
+                Return<void> transStatus = base->getName(
+                        [&outName](const hidl_string& name) {
+                            outName = name.c_str();
+                        });
+                return transStatus.isOk() ? outName : "";
+            }()} {
 }
 
 c2_status_t Codec2ConfigurableClient::query(
@@ -124,7 +121,7 @@
     size_t numIndices = 0;
     for (C2Param* const& stackParam : stackParams) {
         if (!stackParam) {
-            ALOGW("query -- null stack param encountered.");
+            LOG(WARNING) << "query -- null stack param encountered.";
             continue;
         }
         indices[numIndices++] = static_cast<ParamIndex>(stackParam->index());
@@ -139,32 +136,31 @@
         heapParams->reserve(heapParams->size() + numIndices);
     }
     c2_status_t status;
-    Return<void> transStatus = base()->query(
+    Return<void> transStatus = mBase->query(
             indices,
             mayBlock == C2_MAY_BLOCK,
             [&status, &numStackIndices, &stackParams, heapParams](
                     Status s, const Params& p) {
                 status = static_cast<c2_status_t>(s);
                 if (status != C2_OK && status != C2_BAD_INDEX) {
-                    ALOGE("query -- call failed. "
-                            "Error code = %d", static_cast<int>(status));
+                    LOG(DEBUG) << "query -- call failed: "
+                               << status << ".";
                     return;
                 }
                 std::vector<C2Param*> paramPointers;
-                c2_status_t parseStatus = parseParamsBlob(&paramPointers, p);
-                if (parseStatus != C2_OK) {
-                    ALOGE("query -- error while parsing params. "
-                            "Error code = %d", static_cast<int>(status));
-                    status = parseStatus;
+                if (!parseParamsBlob(&paramPointers, p)) {
+                    LOG(ERROR) << "query -- error while parsing params.";
+                    status = C2_CORRUPTED;
                     return;
                 }
                 size_t i = 0;
-                for (auto it = paramPointers.begin(); it != paramPointers.end(); ) {
+                for (auto it = paramPointers.begin();
+                        it != paramPointers.end(); ) {
                     C2Param* paramPointer = *it;
                     if (numStackIndices > 0) {
                         --numStackIndices;
                         if (!paramPointer) {
-                            ALOGW("query -- null stack param.");
+                            LOG(WARNING) << "query -- null stack param.";
                             ++it;
                             continue;
                         }
@@ -172,37 +168,41 @@
                             ++i;
                         }
                         if (i >= stackParams.size()) {
-                            ALOGE("query -- unexpected error.");
+                            LOG(ERROR) << "query -- unexpected error.";
                             status = C2_CORRUPTED;
                             return;
                         }
                         if (stackParams[i]->index() != paramPointer->index()) {
-                            ALOGW("query -- param skipped. index = %d",
-                                    static_cast<int>(stackParams[i]->index()));
+                            LOG(WARNING) << "query -- param skipped: "
+                                            "index = "
+                                         << stackParams[i]->index() << ".";
                             stackParams[i++]->invalidate();
                             continue;
                         }
                         if (!stackParams[i++]->updateFrom(*paramPointer)) {
-                            ALOGW("query -- param update failed. index = %d",
-                                    static_cast<int>(paramPointer->index()));
+                            LOG(WARNING) << "query -- param update failed: "
+                                            "index = "
+                                         << paramPointer->index() << ".";
                         }
                     } else {
                         if (!paramPointer) {
-                            ALOGW("query -- null heap param.");
+                            LOG(WARNING) << "query -- null heap param.";
                             ++it;
                             continue;
                         }
                         if (!heapParams) {
-                            ALOGW("query -- unexpected extra stack param.");
+                            LOG(WARNING) << "query -- "
+                                            "unexpected extra stack param.";
                         } else {
-                            heapParams->emplace_back(C2Param::Copy(*paramPointer));
+                            heapParams->emplace_back(
+                                    C2Param::Copy(*paramPointer));
                         }
                     }
                     ++it;
                 }
             });
     if (!transStatus.isOk()) {
-        ALOGE("query -- transaction failed.");
+        LOG(ERROR) << "query -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
     return status;
@@ -213,13 +213,12 @@
         c2_blocking_t mayBlock,
         std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
     Params hidlParams;
-    Status hidlStatus = createParamsBlob(&hidlParams, params);
-    if (hidlStatus != Status::OK) {
-        ALOGE("config -- bad input.");
+    if (!createParamsBlob(&hidlParams, params)) {
+        LOG(ERROR) << "config -- bad input.";
         return C2_TRANSACTION_FAILED;
     }
     c2_status_t status;
-    Return<void> transStatus = base()->config(
+    Return<void> transStatus = mBase->config(
             hidlParams,
             mayBlock == C2_MAY_BLOCK,
             [&status, &params, failures](
@@ -227,24 +226,27 @@
                     const hidl_vec<SettingResult> f,
                     const Params& o) {
                 status = static_cast<c2_status_t>(s);
-                if (status != C2_OK) {
-                    ALOGD("config -- call failed. "
-                            "Error code = %d", static_cast<int>(status));
+                if (status != C2_OK && status != C2_BAD_INDEX) {
+                    LOG(DEBUG) << "config -- call failed: "
+                               << status << ".";
                 }
                 size_t i = failures->size();
                 failures->resize(i + f.size());
                 for (const SettingResult& sf : f) {
-                    status = objcpy(&(*failures)[i++], sf);
-                    if (status != C2_OK) {
-                        ALOGE("config -- invalid returned SettingResult. "
-                                "Error code = %d", static_cast<int>(status));
+                    if (!objcpy(&(*failures)[i++], sf)) {
+                        LOG(ERROR) << "config -- "
+                                   << "invalid SettingResult returned.";
                         return;
                     }
                 }
-                status = updateParamsFromBlob(params, o);
+                if (!updateParamsFromBlob(params, o)) {
+                    LOG(ERROR) << "config -- "
+                               << "failed to parse returned params.";
+                    status = C2_CORRUPTED;
+                }
             });
     if (!transStatus.isOk()) {
-        ALOGE("config -- transaction failed.");
+        LOG(ERROR) << "config -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
     return status;
@@ -254,7 +256,7 @@
         std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const {
     // TODO: Cache and query properly!
     c2_status_t status;
-    Return<void> transStatus = base()->querySupportedParams(
+    Return<void> transStatus = mBase->querySupportedParams(
             std::numeric_limits<uint32_t>::min(),
             std::numeric_limits<uint32_t>::max(),
             [&status, params](
@@ -262,24 +264,22 @@
                     const hidl_vec<ParamDescriptor>& p) {
                 status = static_cast<c2_status_t>(s);
                 if (status != C2_OK) {
-                    ALOGE("querySupportedParams -- call failed. "
-                            "Error code = %d", static_cast<int>(status));
+                    LOG(DEBUG) << "querySupportedParams -- call failed: "
+                               << status << ".";
                     return;
                 }
                 size_t i = params->size();
                 params->resize(i + p.size());
                 for (const ParamDescriptor& sp : p) {
-                    status = objcpy(&(*params)[i++], sp);
-                    if (status != C2_OK) {
-                        ALOGE("querySupportedParams -- "
-                                "invalid returned ParamDescriptor. "
-                                "Error code = %d", static_cast<int>(status));
+                    if (!objcpy(&(*params)[i++], sp)) {
+                        LOG(ERROR) << "querySupportedParams -- "
+                                   << "invalid returned ParamDescriptor.";
                         return;
                     }
                 }
             });
     if (!transStatus.isOk()) {
-        ALOGE("querySupportedParams -- transaction failed.");
+        LOG(ERROR) << "querySupportedParams -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
     return status;
@@ -290,15 +290,14 @@
         c2_blocking_t mayBlock) const {
     hidl_vec<FieldSupportedValuesQuery> inFields(fields.size());
     for (size_t i = 0; i < fields.size(); ++i) {
-        Status hidlStatus = objcpy(&inFields[i], fields[i]);
-        if (hidlStatus != Status::OK) {
-            ALOGE("querySupportedValues -- bad input");
+        if (!objcpy(&inFields[i], fields[i])) {
+            LOG(ERROR) << "querySupportedValues -- bad input";
             return C2_TRANSACTION_FAILED;
         }
     }
 
     c2_status_t status;
-    Return<void> transStatus = base()->querySupportedValues(
+    Return<void> transStatus = mBase->querySupportedValues(
             inFields,
             mayBlock == C2_MAY_BLOCK,
             [&status, &inFields, &fields](
@@ -306,27 +305,28 @@
                     const hidl_vec<FieldSupportedValuesQueryResult>& r) {
                 status = static_cast<c2_status_t>(s);
                 if (status != C2_OK) {
-                    ALOGE("querySupportedValues -- call failed. "
-                            "Error code = %d", static_cast<int>(status));
+                    LOG(DEBUG) << "querySupportedValues -- call failed: "
+                               << status << ".";
                     return;
                 }
                 if (r.size() != fields.size()) {
-                    ALOGE("querySupportedValues -- input and output lists "
-                            "have different sizes.");
+                    LOG(ERROR) << "querySupportedValues -- "
+                                  "input and output lists "
+                                  "have different sizes.";
                     status = C2_CORRUPTED;
                     return;
                 }
                 for (size_t i = 0; i < fields.size(); ++i) {
-                    status = objcpy(&fields[i], inFields[i], r[i]);
-                    if (status != C2_OK) {
-                        ALOGE("querySupportedValues -- invalid returned value. "
-                                "Error code = %d", static_cast<int>(status));
+                    if (!objcpy(&fields[i], inFields[i], r[i])) {
+                        LOG(ERROR) << "querySupportedValues -- "
+                                      "invalid returned value.";
+                        status = C2_CORRUPTED;
                         return;
                     }
                 }
             });
     if (!transStatus.isOk()) {
-        ALOGE("querySupportedValues -- transaction failed.");
+        LOG(ERROR) << "querySupportedValues -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
     return status;
@@ -339,22 +339,24 @@
 
     virtual Return<void> onWorkDone(const WorkBundle& workBundle) override {
         std::list<std::unique_ptr<C2Work>> workItems;
-        c2_status_t status = objcpy(&workItems, workBundle);
-        if (status != C2_OK) {
-            ALOGI("onWorkDone -- received corrupted WorkBundle. "
-                    "status = %d.", static_cast<int>(status));
+        if (!objcpy(&workItems, workBundle)) {
+            LOG(DEBUG) << "onWorkDone -- received corrupted WorkBundle.";
             return Void();
         }
         // release input buffers potentially held by the component from queue
         size_t numDiscardedInputBuffers = 0;
-        std::shared_ptr<Codec2Client::Component> strongComponent = component.lock();
+        std::shared_ptr<Codec2Client::Component> strongComponent =
+                component.lock();
         if (strongComponent) {
-            numDiscardedInputBuffers = strongComponent->handleOnWorkDone(workItems);
+            numDiscardedInputBuffers =
+                    strongComponent->handleOnWorkDone(workItems);
         }
         if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
-            listener->onWorkDone(component, workItems, numDiscardedInputBuffers);
+            listener->onWorkDone(component,
+                                 workItems,
+                                 numDiscardedInputBuffers);
         } else {
-            ALOGD("onWorkDone -- listener died.");
+            LOG(DEBUG) << "onWorkDone -- listener died.";
         }
         return Void();
     }
@@ -363,13 +365,10 @@
             const hidl_vec<SettingResult>& settingResults) override {
         std::vector<std::shared_ptr<C2SettingResult>> c2SettingResults(
                 settingResults.size());
-        c2_status_t status;
         for (size_t i = 0; i < settingResults.size(); ++i) {
             std::unique_ptr<C2SettingResult> c2SettingResult;
-            status = objcpy(&c2SettingResult, settingResults[i]);
-            if (status != C2_OK) {
-                ALOGI("onTripped -- received corrupted SettingResult. "
-                        "status = %d.", static_cast<int>(status));
+            if (!objcpy(&c2SettingResult, settingResults[i])) {
+                LOG(DEBUG) << "onTripped -- received corrupted SettingResult.";
                 return Void();
             }
             c2SettingResults[i] = std::move(c2SettingResult);
@@ -377,20 +376,21 @@
         if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
             listener->onTripped(component, c2SettingResults);
         } else {
-            ALOGD("onTripped -- listener died.");
+            LOG(DEBUG) << "onTripped -- listener died.";
         }
         return Void();
     }
 
     virtual Return<void> onError(Status s, uint32_t errorCode) override {
-        ALOGD("onError -- status = %d, errorCode = %u.",
-                static_cast<int>(s),
-                static_cast<unsigned>(errorCode));
+        LOG(DEBUG) << "onError --"
+                   << " status = " << s
+                   << ", errorCode = " << errorCode
+                   << ".";
         if (std::shared_ptr<Listener> listener = base.lock()) {
             listener->onError(component, s == Status::OK ?
                     errorCode : static_cast<c2_status_t>(s));
         } else {
-            ALOGD("onError -- listener died.");
+            LOG(DEBUG) << "onError -- listener died.";
         }
         return Void();
     }
@@ -398,55 +398,70 @@
     virtual Return<void> onFramesRendered(
             const hidl_vec<RenderedFrame>& renderedFrames) override {
         std::shared_ptr<Listener> listener = base.lock();
-        std::vector<Codec2Client::Listener::RenderedFrame> rfs;
-        rfs.reserve(renderedFrames.size());
-        for (const RenderedFrame& rf : renderedFrames) {
-            if (rf.slotId >= 0) {
-                if (listener) {
-                    rfs.emplace_back(rf.bufferQueueId,
-                                     rf.slotId,
-                                     rf.timestampNs);
-                }
-            } else {
-                std::shared_ptr<Codec2Client::Component> strongComponent =
-                        component.lock();
-                if (strongComponent) {
-                    uint64_t frameIndex = rf.bufferQueueId;
-                    size_t bufferIndex = static_cast<size_t>(~rf.slotId);
-                    ALOGV("Received death notification of input buffer: "
-                          "frameIndex = %llu, bufferIndex = %zu.",
-                          static_cast<long long unsigned>(frameIndex),
-                          bufferIndex);
-                    std::shared_ptr<C2Buffer> buffer =
-                            strongComponent->freeInputBuffer(
-                                frameIndex, bufferIndex);
-                    if (buffer) {
-                        listener->onInputBufferDone(buffer);
-                    }
-                }
-            }
+        if (!listener) {
+            LOG(DEBUG) << "onFramesRendered -- listener died.";
+            return Void();
         }
-        if (!rfs.empty()) {
-            if (listener) {
-                listener->onFramesRendered(rfs);
-            } else {
-                ALOGD("onFramesRendered -- listener died.");
+        for (const RenderedFrame& renderedFrame : renderedFrames) {
+            listener->onFrameRendered(
+                    renderedFrame.bufferQueueId,
+                    renderedFrame.slotId,
+                    renderedFrame.timestampNs);
+        }
+        return Void();
+    }
+
+    virtual Return<void> onInputBuffersReleased(
+            const hidl_vec<InputBuffer>& inputBuffers) override {
+        std::shared_ptr<Listener> listener = base.lock();
+        if (!listener) {
+            LOG(DEBUG) << "onInputBuffersReleased -- listener died.";
+            return Void();
+        }
+        std::shared_ptr<Codec2Client::Component> strongComponent =
+                component.lock();
+        if (!strongComponent) {
+            LOG(DEBUG) << "onInputBuffersReleased -- component died.";
+            return Void();
+        }
+        for (const InputBuffer& inputBuffer : inputBuffers) {
+            std::shared_ptr<C2Buffer> buffer =
+                    strongComponent->freeInputBuffer(
+                        inputBuffer.frameIndex,
+                        inputBuffer.arrayIndex);
+            LOG(VERBOSE) << "onInputBuffersReleased --"
+                            " received death notification of"
+                            " input buffer:"
+                            " frameIndex = " << inputBuffer.frameIndex
+                         << ", bufferIndex = " << inputBuffer.arrayIndex
+                         << ".";
+            if (buffer) {
+                listener->onInputBufferDone(buffer);
             }
         }
         return Void();
     }
+
 };
 
 // Codec2Client
-Codec2Client::Base* Codec2Client::base() const {
-    return static_cast<Base*>(mBase.get());
-}
-
-Codec2Client::Codec2Client(const sp<Codec2Client::Base>& base, std::string instanceName) :
-    Codec2ConfigurableClient(base), mListed(false), mInstanceName(instanceName) {
+Codec2Client::Codec2Client(const sp<IComponentStore>& base,
+                           std::string serviceName)
+      : Configurable{
+            [base]() -> sp<IConfigurable> {
+                Return<sp<IConfigurable>> transResult =
+                        base->getConfigurable();
+                return transResult.isOk() ?
+                        static_cast<sp<IConfigurable>>(transResult) :
+                        nullptr;
+            }()
+        },
+        mBase{base},
+        mListed{false},
+        mServiceName{serviceName} {
     Return<sp<IClientManager>> transResult = base->getPoolClientManager();
     if (!transResult.isOk()) {
-        ALOGE("getPoolClientManager -- failed transaction.");
+        LOG(ERROR) << "getPoolClientManager -- transaction failed.";
     } else {
         mHostPoolManager = static_cast<sp<IClientManager>>(transResult);
     }
@@ -457,13 +472,10 @@
         const std::shared_ptr<Codec2Client::Listener>& listener,
         std::shared_ptr<Codec2Client::Component>* const component) {
 
-    // TODO: Add support for Bufferpool
-
-
     c2_status_t status;
-    sp<Component::HidlListener> hidlListener = new Component::HidlListener();
+    sp<Component::HidlListener> hidlListener = new Component::HidlListener{};
     hidlListener->base = listener;
-    Return<void> transStatus = base()->createComponent(
+    Return<void> transStatus = mBase->createComponent(
             name,
             hidlListener,
             ClientManager::getInstance(),
@@ -478,23 +490,24 @@
                 hidlListener->component = *component;
             });
     if (!transStatus.isOk()) {
-        ALOGE("createComponent -- failed transaction.");
+        LOG(ERROR) << "createComponent(" << name.c_str()
+                   << ") -- transaction failed.";
         return C2_TRANSACTION_FAILED;
-    }
-
-    if (status != C2_OK) {
+    } else if (status != C2_OK) {
+        LOG(ERROR) << "createComponent(" << name.c_str()
+                   << ") -- call failed: " << status << ".";
         return status;
-    }
-
-    if (!*component) {
-        ALOGE("createComponent -- null component.");
+    } else if (!*component) {
+        LOG(ERROR) << "createComponent(" << name.c_str()
+                   << ") -- null component.";
         return C2_CORRUPTED;
     }
 
     status = (*component)->setDeathListener(*component, listener);
     if (status != C2_OK) {
-        ALOGE("createComponent -- setDeathListener returned error: %d.",
-                static_cast<int>(status));
+        LOG(ERROR) << "createComponent(" << name.c_str()
+                   << ") -- failed to set up death listener: "
+                   << status << ".";
     }
 
     (*component)->mBufferPoolSender.setReceiver(mHostPoolManager);
@@ -505,44 +518,51 @@
         const C2String& name,
         std::shared_ptr<Codec2Client::Interface>* const interface) {
     c2_status_t status;
-    Return<void> transStatus = base()->createInterface(
+    Return<void> transStatus = mBase->createInterface(
             name,
             [&status, interface](
                     Status s,
                     const sp<IComponentInterface>& i) {
                 status = static_cast<c2_status_t>(s);
                 if (status != C2_OK) {
-                    ALOGE("createInterface -- call failed. "
-                            "Error code = %d", static_cast<int>(status));
                     return;
                 }
-                *interface = std::make_shared<Codec2Client::Interface>(i);
+                *interface = std::make_shared<Interface>(i);
             });
     if (!transStatus.isOk()) {
-        ALOGE("createInterface -- failed transaction.");
+        LOG(ERROR) << "createInterface(" << name.c_str()
+                   << ") -- transaction failed.";
         return C2_TRANSACTION_FAILED;
+    } else if (status != C2_OK) {
+        LOG(ERROR) << "createComponent(" << name.c_str()
+                   << ") -- call failed: " << status << ".";
+        return status;
     }
+
     return status;
 }
 
 c2_status_t Codec2Client::createInputSurface(
-        std::shared_ptr<Codec2Client::InputSurface>* const inputSurface) {
-    Return<sp<IInputSurface>> transResult = base()->createInputSurface();
-    if (!transResult.isOk()) {
-        ALOGE("createInputSurface -- failed transaction.");
+        std::shared_ptr<InputSurface>* const inputSurface) {
+    c2_status_t status;
+    Return<void> transStatus = mBase->createInputSurface(
+            [&status, inputSurface](
+                    Status s,
+                    const sp<IInputSurface>& i) {
+                status = static_cast<c2_status_t>(s);
+                if (status != C2_OK) {
+                    return;
+                }
+                *inputSurface = std::make_shared<InputSurface>(i);
+            });
+    if (!transStatus.isOk()) {
+        LOG(ERROR) << "createInputSurface -- transaction failed.";
         return C2_TRANSACTION_FAILED;
+    } else if (status != C2_OK) {
+        LOG(DEBUG) << "createInputSurface -- call failed: "
+                   << status << ".";
     }
-    sp<IInputSurface> result = static_cast<sp<IInputSurface>>(transResult);
-    if (!result) {
-        *inputSurface = nullptr;
-        return C2_OK;
-    }
-    *inputSurface = std::make_shared<InputSurface>(result);
-    if (!*inputSurface) {
-        ALOGE("createInputSurface -- unknown error.");
-        return C2_CORRUPTED;
-    }
-    return C2_OK;
+    return status;
 }
 
 const std::vector<C2Component::Traits>& Codec2Client::listComponents() const {
@@ -550,22 +570,26 @@
     if (mListed) {
         return mTraitsList;
     }
-    Return<void> transStatus = base()->listComponents(
-            [this](const hidl_vec<IComponentStore::ComponentTraits>& t) {
+    Return<void> transStatus = mBase->listComponents(
+            [this](Status s,
+                   const hidl_vec<IComponentStore::ComponentTraits>& t) {
+                if (s != Status::OK) {
+                    LOG(DEBUG) << "listComponents -- call failed: "
+                               << static_cast<c2_status_t>(s) << ".";
+                    return;
+                }
                 mTraitsList.resize(t.size());
                 mAliasesBuffer.resize(t.size());
                 for (size_t i = 0; i < t.size(); ++i) {
-                    c2_status_t status = objcpy(
-                            &mTraitsList[i], &mAliasesBuffer[i], t[i]);
-                    mTraitsList[i].owner = mInstanceName;
-                    if (status != C2_OK) {
-                        ALOGE("listComponents -- corrupted output.");
+                    if (!objcpy(&mTraitsList[i], &mAliasesBuffer[i], t[i])) {
+                        LOG(ERROR) << "listComponents -- corrupted output.";
                         return;
                     }
+                    mTraitsList[i].owner = mServiceName;
                 }
             });
     if (!transStatus.isOk()) {
-        ALOGE("listComponents -- failed transaction.");
+        LOG(ERROR) << "listComponents -- transaction failed.";
     }
     mListed = true;
     return mTraitsList;
@@ -577,7 +601,7 @@
     // TODO: Implement?
     (void)src;
     (void)dst;
-    ALOGE("copyBuffer not implemented");
+    LOG(ERROR) << "copyBuffer not implemented";
     return C2_OMITTED;
 }
 
@@ -597,21 +621,25 @@
                             const hidl_vec<StructDescriptor>& sd) {
                         c2_status_t status = static_cast<c2_status_t>(s);
                         if (status != C2_OK) {
-                            ALOGE("getStructDescriptors -- call failed. "
-                                    "Error code = %d", static_cast<int>(status));
+                            LOG(DEBUG) << "SimpleParamReflector -- "
+                                          "getStructDescriptors() failed: "
+                                       << status << ".";
                             descriptor.reset();
                             return;
                         }
                         if (sd.size() != 1) {
-                            ALOGD("getStructDescriptors -- returned vector of size %zu.",
-                                    sd.size());
+                            LOG(DEBUG) << "SimpleParamReflector -- "
+                                          "getStructDescriptors() "
+                                          "returned vector of size "
+                                       << sd.size() << ". "
+                                          "It should be 1.";
                             descriptor.reset();
                             return;
                         }
-                        status = objcpy(&descriptor, sd[0]);
-                        if (status != C2_OK) {
-                            ALOGD("getStructDescriptors -- failed to convert. "
-                                    "Error code = %d", static_cast<int>(status));
+                        if (!objcpy(&descriptor, sd[0])) {
+                            LOG(DEBUG) << "SimpleParamReflector -- "
+                                          "getStructDescriptors() returned "
+                                          "corrupted data.";
                             descriptor.reset();
                             return;
                         }
@@ -625,44 +653,44 @@
         sp<Base> mBase;
     };
 
-    return std::make_shared<SimpleParamReflector>(base());
+    return std::make_shared<SimpleParamReflector>(mBase);
 };
 
 std::shared_ptr<Codec2Client> Codec2Client::CreateFromService(
-        const char* instanceName, bool waitForService) {
-    if (!instanceName) {
+        const char* serviceName, bool waitForService) {
+    if (!serviceName) {
         return nullptr;
     }
     sp<Base> baseStore = waitForService ?
-            Base::getService(instanceName) :
-            Base::tryGetService(instanceName);
+            Base::getService(serviceName) :
+            Base::tryGetService(serviceName);
     if (!baseStore) {
         if (waitForService) {
-            ALOGW("Codec2.0 service \"%s\" inaccessible. "
-                  "Check the device manifest.",
-                  instanceName);
+            LOG(WARNING) << "Codec2.0 service \"" << serviceName << "\""
+                            " inaccessible. Check the device manifest.";
         } else {
-            ALOGD("Codec2.0 service \"%s\" unavailable right now. "
-                  "Try again later.",
-                  instanceName);
+            LOG(DEBUG) << "Codec2.0 service \"" << serviceName << "\""
+                          " unavailable at the moment. "
+                          " Wait or check the device manifest.";
         }
         return nullptr;
     }
-    return std::make_shared<Codec2Client>(baseStore, instanceName);
+    return std::make_shared<Codec2Client>(baseStore, serviceName);
 }
 
 c2_status_t Codec2Client::ForAllStores(
         const std::string &key,
-        std::function<c2_status_t(const std::shared_ptr<Codec2Client>&)> predicate) {
+        std::function<c2_status_t(const std::shared_ptr<Codec2Client>&)>
+            predicate) {
     c2_status_t status = C2_NO_INIT;  // no IComponentStores present
 
     // Cache the mapping key -> index of Codec2Client in getClient().
     static std::mutex key2IndexMutex;
     static std::map<std::string, size_t> key2Index;
 
-    // By default try all stores. However, try the last known client first. If the last known
-    // client fails, retry once. We do this by pushing the last known client in front of the
-    // list of all clients.
+    // By default try all stores. However, try the last known client first. If
+    // the last known client fails, retry once. We do this by pushing the last
+    // known client in front of the list of all clients.
     std::deque<size_t> indices;
     for (size_t index = kNumClients; index > 0; ) {
         indices.push_front(--index);
@@ -688,7 +716,8 @@
             }
         }
         if (wasMapped) {
-            ALOGI("Could not find '%s' in last instance. Retrying...", key.c_str());
+            LOG(INFO) << "Could not find \"" << key << "\""
+                         " in the last instance. Retrying...";
             wasMapped = false;
         }
     }
@@ -704,20 +733,27 @@
     c2_status_t status = ForAllStores(
             componentName,
             [owner, &component, componentName, &listener](
-                    const std::shared_ptr<Codec2Client> &client) -> c2_status_t {
-                c2_status_t status = client->createComponent(componentName, listener, &component);
+                    const std::shared_ptr<Codec2Client> &client)
+                        -> c2_status_t {
+                c2_status_t status = client->createComponent(componentName,
+                                                             listener,
+                                                             &component);
                 if (status == C2_OK) {
                     if (owner) {
                         *owner = client;
                     }
                 } else if (status != C2_NOT_FOUND) {
-                    ALOGD("IComponentStore(%s)::createComponent('%s') returned %s",
-                            client->getInstanceName().c_str(), componentName, asString(status));
+                    LOG(DEBUG) << "IComponentStore("
+                                   << client->getServiceName()
+                               << ")::createComponent(\"" << componentName
+                               << "\") returned status = "
+                               << status << ".";
                 }
                 return status;
             });
     if (status != C2_OK) {
-        ALOGI("Could not create component '%s' (%s)", componentName, asString(status));
+        LOG(DEBUG) << "Could not create component \"" << componentName << "\". "
+                      "Status = " << status << ".";
     }
     return component;
 }
@@ -730,20 +766,26 @@
     c2_status_t status = ForAllStores(
             interfaceName,
             [owner, &interface, interfaceName](
-                    const std::shared_ptr<Codec2Client> &client) -> c2_status_t {
-                c2_status_t status = client->createInterface(interfaceName, &interface);
+                    const std::shared_ptr<Codec2Client> &client)
+                        -> c2_status_t {
+                c2_status_t status = client->createInterface(interfaceName,
+                                                             &interface);
                 if (status == C2_OK) {
                     if (owner) {
                         *owner = client;
                     }
                 } else if (status != C2_NOT_FOUND) {
-                    ALOGD("IComponentStore(%s)::createInterface('%s') returned %s",
-                            client->getInstanceName().c_str(), interfaceName, asString(status));
+                    LOG(DEBUG) << "IComponentStore("
+                                   << client->getServiceName()
+                               << ")::createInterface(\"" << interfaceName
+                               << "\") returned status = "
+                               << status << ".";
                 }
                 return status;
             });
     if (status != C2_OK) {
-        ALOGI("Could not create interface '%s' (%s)", interfaceName, asString(status));
+        LOG(DEBUG) << "Could not create interface \"" << interfaceName << "\". "
+                      "Status = " << status << ".";
     }
     return interface;
 }
@@ -762,7 +804,8 @@
             }
         }
     }
-    ALOGW("Could not create an input surface from any Codec2.0 services.");
+    LOG(INFO) << "Could not create an input surface "
+                 "from any Codec2.0 services.";
     return nullptr;
 }
 
@@ -798,15 +841,39 @@
 Codec2Client::Listener::~Listener() {
 }
 
-// Codec2Client::Component
-
-Codec2Client::Component::Base* Codec2Client::Component::base() const {
-    return static_cast<Base*>(mBase.get());
+// Codec2Client::Interface
+Codec2Client::Interface::Interface(const sp<Base>& base)
+      : Configurable{
+            [base]() -> sp<IConfigurable> {
+                Return<sp<IConfigurable>> transResult =
+                        base->getConfigurable();
+                return transResult.isOk() ?
+                        static_cast<sp<IConfigurable>>(transResult) :
+                        nullptr;
+            }()
+        },
+        mBase{base} {
 }
 
-Codec2Client::Component::Component(const sp<Codec2Client::Component::Base>& base) :
-    Codec2Client::Configurable(base),
-    mBufferPoolSender(nullptr) {
+// Codec2Client::Component
+Codec2Client::Component::Component(const sp<Base>& base)
+      : Configurable{
+            [base]() -> sp<IConfigurable> {
+                Return<sp<IComponentInterface>> transResult1 =
+                        base->getInterface();
+                if (!transResult1.isOk()) {
+                    return nullptr;
+                }
+                Return<sp<IConfigurable>> transResult2 =
+                        static_cast<sp<IComponentInterface>>(transResult1)->
+                        getConfigurable();
+                return transResult2.isOk() ?
+                        static_cast<sp<IConfigurable>>(transResult2) :
+                        nullptr;
+            }()
+        },
+        mBase{base},
+        mBufferPoolSender{nullptr} {
 }
 
 Codec2Client::Component::~Component() {
@@ -817,7 +884,7 @@
         C2BlockPool::local_id_t* blockPoolId,
         std::shared_ptr<Codec2Client::Configurable>* configurable) {
     c2_status_t status;
-    Return<void> transStatus = base()->createBlockPool(
+    Return<void> transStatus = mBase->createBlockPool(
             static_cast<uint32_t>(id),
             [&status, blockPoolId, configurable](
                     Status s,
@@ -826,15 +893,15 @@
                 status = static_cast<c2_status_t>(s);
                 configurable->reset();
                 if (status != C2_OK) {
-                    ALOGE("createBlockPool -- call failed. "
-                            "Error code = %d", static_cast<int>(status));
+                    LOG(DEBUG) << "createBlockPool -- call failed: "
+                               << status << ".";
                     return;
                 }
                 *blockPoolId = static_cast<C2BlockPool::local_id_t>(pId);
-                *configurable = std::make_shared<Codec2Client::Configurable>(c);
+                *configurable = std::make_shared<Configurable>(c);
             });
     if (!transStatus.isOk()) {
-        ALOGE("createBlockPool -- transaction failed.");
+        LOG(ERROR) << "createBlockPool -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
     return status;
@@ -842,10 +909,10 @@
 
 c2_status_t Codec2Client::Component::destroyBlockPool(
         C2BlockPool::local_id_t localId) {
-    Return<Status> transResult = base()->destroyBlockPool(
+    Return<Status> transResult = mBase->destroyBlockPool(
             static_cast<uint64_t>(localId));
     if (!transResult.isOk()) {
-        ALOGE("destroyBlockPool -- transaction failed.");
+        LOG(ERROR) << "destroyBlockPool -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
     return static_cast<c2_status_t>(static_cast<Status>(transResult));
@@ -859,7 +926,8 @@
         if (work) {
             if (work->worklets.empty()
                     || !work->worklets.back()
-                    || (work->worklets.back()->output.flags & C2FrameData::FLAG_INCOMPLETE) == 0) {
+                    || (work->worklets.back()->output.flags &
+                        C2FrameData::FLAG_INCOMPLETE) == 0) {
                 // input is complete
                 inputDone.emplace_back(work->input.ordinal.frameIndex.peeku());
             }
@@ -872,13 +940,14 @@
         for (uint64_t inputIndex : inputDone) {
             auto it = mInputBuffers.find(inputIndex);
             if (it == mInputBuffers.end()) {
-                ALOGV("onWorkDone -- returned consumed/unknown "
-                      "input frame: index %llu",
-                        (long long)inputIndex);
+                LOG(VERBOSE) << "onWorkDone -- returned consumed/unknown "
+                                "input frame: index = "
+                             << inputIndex << ".";
             } else {
-                ALOGV("onWorkDone -- processed input frame: "
-                      "index %llu (containing %zu buffers)",
-                        (long long)inputIndex, it->second.size());
+                LOG(VERBOSE) << "onWorkDone -- processed input frame: "
+                             << inputIndex
+                             << " (containing " << it->second.size()
+                                 << " buffers).";
                 mInputBuffers.erase(it);
                 mInputBufferCount.erase(inputIndex);
                 ++numDiscardedInputBuffers;
@@ -906,21 +975,21 @@
     std::lock_guard<std::mutex> lock(mInputBuffersMutex);
     auto it = mInputBuffers.find(frameIndex);
     if (it == mInputBuffers.end()) {
-        ALOGI("freeInputBuffer -- Unrecognized input frame index %llu.",
-              static_cast<long long unsigned>(frameIndex));
+        LOG(INFO) << "freeInputBuffer -- Unrecognized input frame index "
+                  << frameIndex << ".";
         return nullptr;
     }
     if (bufferIndex >= it->second.size()) {
-        ALOGI("freeInputBuffer -- Input buffer no. %zu is invalid in "
-              "input frame index %llu.",
-              bufferIndex, static_cast<long long unsigned>(frameIndex));
+        LOG(INFO) << "freeInputBuffer -- Input buffer number " << bufferIndex
+                  << " is not valid in input with frame index " << frameIndex
+                  << ".";
         return nullptr;
     }
     buffer = it->second[bufferIndex];
     if (!buffer) {
-        ALOGI("freeInputBuffer -- Input buffer no. %zu in "
-              "input frame index %llu has already been freed.",
-              bufferIndex, static_cast<long long unsigned>(frameIndex));
+        LOG(INFO) << "freeInputBuffer -- Input buffer number " << bufferIndex
+                  << " in input with frame index " << frameIndex
+                  << " has already been freed.";
         return nullptr;
     }
     it->second[bufferIndex] = nullptr;
@@ -949,33 +1018,33 @@
             if (!res.second) {
                 // TODO: append? - for now we are replacing
                 res.first->second = work->input.buffers;
-                ALOGI("queue -- duplicate input frame: index %llu. "
-                      "Discarding the old input frame...",
-                        (long long)inputIndex);
+                LOG(INFO) << "queue -- duplicate input frame index: "
+                          << inputIndex
+                          << ". Discarding the old input frame...";
             }
             mInputBufferCount[inputIndex] = work->input.buffers.size();
-            ALOGV("queue -- queueing input frame: "
-                  "index %llu (containing %zu buffers)",
-                    (long long)inputIndex, work->input.buffers.size());
+            LOG(VERBOSE) << "queue -- queuing input frame: "
+                         << "index = " << inputIndex
+                         << ", number of buffers = "
+                             << work->input.buffers.size()
+                         << ".";
         }
     }
 
     WorkBundle workBundle;
-    Status hidlStatus = objcpy(&workBundle, *items, &mBufferPoolSender);
-    if (hidlStatus != Status::OK) {
-        ALOGE("queue -- bad input.");
+    if (!objcpy(&workBundle, *items, &mBufferPoolSender)) {
+        LOG(ERROR) << "queue -- bad input.";
         return C2_TRANSACTION_FAILED;
     }
-    Return<Status> transStatus = base()->queue(workBundle);
+    Return<Status> transStatus = mBase->queue(workBundle);
     if (!transStatus.isOk()) {
-        ALOGE("queue -- transaction failed.");
+        LOG(ERROR) << "queue -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
     c2_status_t status =
             static_cast<c2_status_t>(static_cast<Status>(transStatus));
     if (status != C2_OK) {
-        ALOGE("queue -- call failed. "
-                "Error code = %d", static_cast<int>(status));
+        LOG(DEBUG) << "queue -- call failed: " << status << ".";
     }
     return status;
 }
@@ -985,19 +1054,22 @@
         std::list<std::unique_ptr<C2Work>>* const flushedWork) {
     (void)mode; // Flush mode isn't supported in HIDL yet.
     c2_status_t status;
-    Return<void> transStatus = base()->flush(
+    Return<void> transStatus = mBase->flush(
             [&status, flushedWork](
                     Status s, const WorkBundle& wb) {
                 status = static_cast<c2_status_t>(s);
                 if (status != C2_OK) {
-                    ALOGE("flush -- call failed. "
-                            "Error code = %d", static_cast<int>(status));
+                    LOG(DEBUG) << "flush -- call failed: " << status << ".";
                     return;
                 }
-                status = objcpy(flushedWork, wb);
+                if (!objcpy(flushedWork, wb)) {
+                    status = C2_CORRUPTED;
+                } else {
+                    status = C2_OK;
+                }
             });
     if (!transStatus.isOk()) {
-        ALOGE("flush -- transaction failed.");
+        LOG(ERROR) << "flush -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
 
@@ -1021,13 +1093,14 @@
         std::lock_guard<std::mutex> lock(mInputBuffersMutex);
         auto it = mInputBuffers.find(flushedIndex);
         if (it == mInputBuffers.end()) {
-            ALOGV("flush -- returned consumed/unknown input frame: "
-                  "index %llu",
-                    (long long)flushedIndex);
+            LOG(VERBOSE) << "flush -- returned consumed/unknown input frame: "
+                            "index = " << flushedIndex << ".";
         } else {
-            ALOGV("flush -- returned unprocessed input frame: "
-                  "index %llu (containing %zu buffers)",
-                    (long long)flushedIndex, mInputBufferCount[flushedIndex]);
+            LOG(VERBOSE) << "flush -- returned unprocessed input frame: "
+                            "index = " << flushedIndex
+                         << ", number of buffers = "
+                             << mInputBufferCount[flushedIndex]
+                         << ".";
             mInputBuffers.erase(it);
             mInputBufferCount.erase(flushedIndex);
         }
@@ -1048,47 +1121,44 @@
 }
 
 c2_status_t Codec2Client::Component::drain(C2Component::drain_mode_t mode) {
-    Return<Status> transStatus = base()->drain(
+    Return<Status> transStatus = mBase->drain(
             mode == C2Component::DRAIN_COMPONENT_WITH_EOS);
     if (!transStatus.isOk()) {
-        ALOGE("drain -- transaction failed.");
+        LOG(ERROR) << "drain -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
     c2_status_t status =
             static_cast<c2_status_t>(static_cast<Status>(transStatus));
     if (status != C2_OK) {
-        ALOGE("drain -- call failed. "
-                "Error code = %d", static_cast<int>(status));
+        LOG(DEBUG) << "drain -- call failed: " << status << ".";
     }
     return status;
 }
 
 c2_status_t Codec2Client::Component::start() {
-    Return<Status> transStatus = base()->start();
+    Return<Status> transStatus = mBase->start();
     if (!transStatus.isOk()) {
-        ALOGE("start -- transaction failed.");
+        LOG(ERROR) << "start -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
     c2_status_t status =
             static_cast<c2_status_t>(static_cast<Status>(transStatus));
     if (status != C2_OK) {
-        ALOGE("start -- call failed. "
-                "Error code = %d", static_cast<int>(status));
+        LOG(DEBUG) << "start -- call failed: " << status << ".";
     }
     return status;
 }
 
 c2_status_t Codec2Client::Component::stop() {
-    Return<Status> transStatus = base()->stop();
+    Return<Status> transStatus = mBase->stop();
     if (!transStatus.isOk()) {
-        ALOGE("stop -- transaction failed.");
+        LOG(ERROR) << "stop -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
     c2_status_t status =
             static_cast<c2_status_t>(static_cast<Status>(transStatus));
     if (status != C2_OK) {
-        ALOGE("stop -- call failed. "
-                "Error code = %d", static_cast<int>(status));
+        LOG(DEBUG) << "stop -- call failed: " << status << ".";
     }
     mInputBuffersMutex.lock();
     mInputBuffers.clear();
@@ -1098,16 +1168,15 @@
 }
 
 c2_status_t Codec2Client::Component::reset() {
-    Return<Status> transStatus = base()->reset();
+    Return<Status> transStatus = mBase->reset();
     if (!transStatus.isOk()) {
-        ALOGE("reset -- transaction failed.");
+        LOG(ERROR) << "reset -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
     c2_status_t status =
             static_cast<c2_status_t>(static_cast<Status>(transStatus));
     if (status != C2_OK) {
-        ALOGE("reset -- call failed. "
-                "Error code = %d", static_cast<int>(status));
+        LOG(DEBUG) << "reset -- call failed: " << status << ".";
     }
     mInputBuffersMutex.lock();
     mInputBuffers.clear();
@@ -1117,16 +1186,15 @@
 }
 
 c2_status_t Codec2Client::Component::release() {
-    Return<Status> transStatus = base()->release();
+    Return<Status> transStatus = mBase->release();
     if (!transStatus.isOk()) {
-        ALOGE("release -- transaction failed.");
+        LOG(ERROR) << "release -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
     c2_status_t status =
             static_cast<c2_status_t>(static_cast<Status>(transStatus));
     if (status != C2_OK) {
-        ALOGE("release -- call failed. "
-                "Error code = %d", static_cast<int>(status));
+        LOG(DEBUG) << "release -- call failed: " << status << ".";
     }
     mInputBuffersMutex.lock();
     mInputBuffers.clear();
@@ -1144,17 +1212,16 @@
         igbp = new TWGraphicBufferProducer<HGraphicBufferProducer>(surface);
     }
 
-    Return<Status> transStatus = base()->setOutputSurface(
+    Return<Status> transStatus = mBase->setOutputSurface(
             static_cast<uint64_t>(blockPoolId), igbp);
     if (!transStatus.isOk()) {
-        ALOGE("setOutputSurface -- transaction failed.");
+        LOG(ERROR) << "setOutputSurface -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
     c2_status_t status =
             static_cast<c2_status_t>(static_cast<Status>(transStatus));
     if (status != C2_OK) {
-        ALOGE("setOutputSurface -- call failed. "
-                "Error code = %d", static_cast<int>(status));
+        LOG(DEBUG) << "setOutputSurface -- call failed: " << status << ".";
     } else {
         std::lock_guard<std::mutex> lock(mOutputBufferQueueMutex);
         if (mOutputIgbp != surface) {
@@ -1162,7 +1229,8 @@
             if (!surface) {
                 mOutputBqId = 0;
             } else if (surface->getUniqueId(&mOutputBqId) != OK) {
-                ALOGE("setOutputSurface -- cannot obtain bufferqueue id.");
+                LOG(ERROR) << "setOutputSurface -- "
+                              "cannot obtain bufferqueue id.";
             }
         }
         mOutputGeneration = generation;
@@ -1191,17 +1259,16 @@
                                                outputGeneration,
                                                &bqSlot);
         if (status != OK) {
-            ALOGW("queueToOutputSurface -- attaching failed.");
+            LOG(WARNING) << "queueToOutputSurface -- attaching failed.";
             return INVALID_OPERATION;
         }
 
         status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
                                          input, output);
         if (status != OK) {
-            ALOGE("queueToOutputSurface -- queueBuffer() failed "
-                    "on non-bufferqueue-based block. "
-                    "Error code = %d.",
-                    static_cast<int>(status));
+            LOG(ERROR) << "queueToOutputSurface -- queueBuffer() failed "
+                          "on non-bufferqueue-based block. "
+                          "Error = " << status << ".";
             return status;
         }
         return OK;
@@ -1214,17 +1281,17 @@
     mOutputBufferQueueMutex.unlock();
 
     if (!outputIgbp) {
-        ALOGV("queueToOutputSurface -- output surface is null.");
+        LOG(VERBOSE) << "queueToOutputSurface -- output surface is null.";
         return NO_INIT;
     }
 
     if (bqId != outputBqId || generation != outputGeneration) {
         if (!holdBufferQueueBlock(block, mOutputIgbp, mOutputBqId, mOutputGeneration)) {
-            ALOGE("queueToOutputSurface -- migration fialed");
+            LOG(ERROR) << "queueToOutputSurface -- migration failed.";
             return DEAD_OBJECT;
         }
         if (!getBufferQueueAssignment(block, &generation, &bqId, &bqSlot)) {
-            ALOGE("queueToOutputSurface -- corrupted bq assignment");
+            LOG(ERROR) << "queueToOutputSurface -- corrupted bufferqueue assignment.";
             return UNKNOWN_ERROR;
         }
     }
@@ -1232,49 +1299,77 @@
     status_t status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
                                               input, output);
     if (status != OK) {
-        ALOGD("queueToOutputSurface -- queueBuffer() failed "
-                "on bufferqueue-based block. "
-                "Error code = %d.",
-                static_cast<int>(status));
+        LOG(DEBUG) << "queueToOutputSurface -- queueBuffer() failed "
+                      "on bufferqueue-based block. "
+                      "Error = " << status << ".";
         return status;
     }
     if (!yieldBufferQueueBlock(block)) {
-        ALOGD("queueToOutputSurface -- cannot yield bufferqueue-based block "
-                "to the bufferqueue.");
+        LOG(DEBUG) << "queueToOutputSurface -- cannot yield "
+                      "bufferqueue-based block to the bufferqueue.";
         return UNKNOWN_ERROR;
     }
     return OK;
 }
 
-c2_status_t Codec2Client::Component::connectToOmxInputSurface(
-        const sp<HGraphicBufferProducer>& producer,
-        const sp<HGraphicBufferSource>& source) {
-    Return<Status> transStatus = base()->connectToOmxInputSurface(
-            producer, source);
+c2_status_t Codec2Client::Component::connectToInputSurface(
+        const std::shared_ptr<InputSurface>& inputSurface,
+        std::shared_ptr<InputSurfaceConnection>* connection) {
+    c2_status_t status;
+    Return<void> transStatus = mBase->connectToInputSurface(
+            inputSurface->mBase,
+            [&status, connection](
+                    Status s, const sp<IInputSurfaceConnection>& c) {
+                status = static_cast<c2_status_t>(s);
+                if (status != C2_OK) {
+                    LOG(DEBUG) << "connectToInputSurface -- call failed: "
+                               << status << ".";
+                    return;
+                }
+                *connection = std::make_shared<InputSurfaceConnection>(c);
+            });
     if (!transStatus.isOk()) {
-        ALOGE("connectToOmxInputSurface -- transaction failed.");
+        LOG(ERROR) << "connectToInputSurface -- transaction failed";
         return C2_TRANSACTION_FAILED;
     }
-    c2_status_t status =
-            static_cast<c2_status_t>(static_cast<Status>(transStatus));
-    if (status != C2_OK) {
-        ALOGE("connectToOmxInputSurface -- call failed. "
-                "Error code = %d", static_cast<int>(status));
+    return status;
+}
+
+c2_status_t Codec2Client::Component::connectToOmxInputSurface(
+        const sp<HGraphicBufferProducer>& producer,
+        const sp<HGraphicBufferSource>& source,
+        std::shared_ptr<InputSurfaceConnection>* connection) {
+    c2_status_t status;
+    Return<void> transStatus = mBase->connectToOmxInputSurface(
+            producer, source,
+            [&status, connection](
+                    Status s, const sp<IInputSurfaceConnection>& c) {
+                status = static_cast<c2_status_t>(s);
+                if (status != C2_OK) {
+                    LOG(DEBUG) << "connectToOmxInputSurface -- call failed: "
+                               << status << ".";
+                    return;
+                }
+                *connection = std::make_shared<InputSurfaceConnection>(c);
+            });
+    if (!transStatus.isOk()) {
+        LOG(ERROR) << "connectToOmxInputSurface -- transaction failed.";
+        return C2_TRANSACTION_FAILED;
     }
     return status;
 }
 
 c2_status_t Codec2Client::Component::disconnectFromInputSurface() {
-    Return<Status> transStatus = base()->disconnectFromInputSurface();
+    Return<Status> transStatus = mBase->disconnectFromInputSurface();
     if (!transStatus.isOk()) {
-        ALOGE("disconnectToInputSurface -- transaction failed.");
+        LOG(ERROR) << "disconnectToInputSurface -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
     c2_status_t status =
             static_cast<c2_status_t>(static_cast<Status>(transStatus));
     if (status != C2_OK) {
-        ALOGE("disconnectFromInputSurface -- call failed. "
-                "Error code = %d", static_cast<int>(status));
+        LOG(DEBUG) << "disconnectFromInputSurface -- call failed: "
+                   << status << ".";
     }
     return status;
 }
@@ -1294,7 +1389,7 @@
             if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
                 listener->onDeath(component);
             } else {
-                ALOGW("onDeath -- listener died.");
+                LOG(DEBUG) << "onDeath -- listener died.";
             }
         }
     };
@@ -1304,93 +1399,68 @@
     deathRecipient->component = component;
 
     component->mDeathRecipient = deathRecipient;
-    Return<bool> transResult = component->base()->linkToDeath(
+    Return<bool> transResult = component->mBase->linkToDeath(
             component->mDeathRecipient, 0);
     if (!transResult.isOk()) {
-        ALOGE("setDeathListener -- failed transaction: linkToDeath.");
+        LOG(ERROR) << "setDeathListener -- linkToDeath() transaction failed.";
         return C2_TRANSACTION_FAILED;
     }
     if (!static_cast<bool>(transResult)) {
-        ALOGE("setDeathListener -- linkToDeath call failed.");
+        LOG(DEBUG) << "setDeathListener -- linkToDeath() call failed.";
         return C2_CORRUPTED;
     }
     return C2_OK;
 }
 
 // Codec2Client::InputSurface
-
-Codec2Client::InputSurface::Base* Codec2Client::InputSurface::base() const {
-    return static_cast<Base*>(mBase.get());
-}
-
-Codec2Client::InputSurface::InputSurface(const sp<IInputSurface>& base) :
-    mBase(base),
-    mGraphicBufferProducer(new
+Codec2Client::InputSurface::InputSurface(const sp<IInputSurface>& base)
+      : Configurable{
+            [base]() -> sp<IConfigurable> {
+                Return<sp<IConfigurable>> transResult =
+                        base->getConfigurable();
+                return transResult.isOk() ?
+                        static_cast<sp<IConfigurable>>(transResult) :
+                        nullptr;
+            }()
+        },
+        mBase{base},
+        mGraphicBufferProducer{new
             ::android::hardware::graphics::bufferqueue::V1_0::utils::
-            H2BGraphicBufferProducer(base)) {
+            H2BGraphicBufferProducer([base]() -> sp<HGraphicBufferProducer> {
+                Return<sp<HGraphicBufferProducer>> transResult =
+                        base->getGraphicBufferProducer();
+                return transResult.isOk() ?
+                        static_cast<sp<HGraphicBufferProducer>>(transResult) :
+                        nullptr;
+            }())} {
 }
 
-c2_status_t Codec2Client::InputSurface::connectToComponent(
-        const std::shared_ptr<Codec2Client::Component>& component,
-        std::shared_ptr<Connection>* connection) {
-    c2_status_t status;
-    Return<void> transStatus = base()->connectToComponent(
-        component->base(),
-        [&status, connection](
-                Status s,
-                const sp<IInputSurfaceConnection>& c) {
-            status = static_cast<c2_status_t>(s);
-            if (status != C2_OK) {
-                ALOGE("connectToComponent -- call failed. "
-                        "Error code = %d", static_cast<int>(status));
-                return;
-            }
-            *connection = std::make_shared<Connection>(c);
-        });
-    if (!transStatus.isOk()) {
-        ALOGE("connect -- transaction failed.");
-        return C2_TRANSACTION_FAILED;
-    }
-    return status;
-}
-
-std::shared_ptr<Codec2Client::Configurable>
-        Codec2Client::InputSurface::getConfigurable() const {
-    Return<sp<IConfigurable>> transResult = base()->getConfigurable();
-    if (!transResult.isOk()) {
-        ALOGW("getConfigurable -- transaction failed.");
-        return nullptr;
-    }
-    if (!static_cast<sp<IConfigurable>>(transResult)) {
-        ALOGW("getConfigurable -- null pointer.");
-        return nullptr;
-    }
-    return std::make_shared<Configurable>(transResult);
-}
-
-const sp<IGraphicBufferProducer>&
+sp<IGraphicBufferProducer>
         Codec2Client::InputSurface::getGraphicBufferProducer() const {
     return mGraphicBufferProducer;
 }
 
-const sp<IInputSurface>& Codec2Client::InputSurface::getHalInterface() const {
+sp<IInputSurface> Codec2Client::InputSurface::getHalInterface() const {
     return mBase;
 }
 
 // Codec2Client::InputSurfaceConnection
-
-Codec2Client::InputSurfaceConnection::Base*
-        Codec2Client::InputSurfaceConnection::base() const {
-    return static_cast<Base*>(mBase.get());
-}
-
 Codec2Client::InputSurfaceConnection::InputSurfaceConnection(
-        const sp<Codec2Client::InputSurfaceConnection::Base>& base) :
-    mBase(base) {
+        const sp<IInputSurfaceConnection>& base)
+      : Configurable{
+            [base]() -> sp<IConfigurable> {
+                Return<sp<IConfigurable>> transResult =
+                        base->getConfigurable();
+                return transResult.isOk() ?
+                        static_cast<sp<IConfigurable>>(transResult) :
+                        nullptr;
+            }()
+        },
+        mBase{base} {
 }
 
 c2_status_t Codec2Client::InputSurfaceConnection::disconnect() {
-    Return<Status> transResult = base()->disconnect();
+    Return<Status> transResult = mBase->disconnect();
     return static_cast<c2_status_t>(static_cast<Status>(transResult));
 }
 
diff --git a/media/codec2/hidl/client/include/codec2/hidl/client.h b/media/codec2/hidl/client/include/codec2/hidl/client.h
index c48bf0c..f320ef3 100644
--- a/media/codec2/hidl/client/include/codec2/hidl/client.h
+++ b/media/codec2/hidl/client/include/codec2/hidl/client.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef CODEC2_HIDL_CLIENT_H_
-#define CODEC2_HIDL_CLIENT_H_
+#ifndef CODEC2_HIDL_CLIENT_H
+#define CODEC2_HIDL_CLIENT_H
 
 #include <gui/IGraphicBufferProducer.h>
 #include <codec2/hidl/1.0/types.h>
@@ -70,8 +70,8 @@
 namespace c2 {
 namespace V1_0 {
 struct IConfigurable;
-struct IComponentInterface;
 struct IComponent;
+struct IComponentInterface;
 struct IComponentStore;
 struct IInputSurface;
 struct IInputSurfaceConnection;
@@ -146,10 +146,8 @@
     Codec2ConfigurableClient(const sp<Base>& base);
 
 protected:
-    C2String mName;
     sp<Base> mBase;
-
-    Base* base() const;
+    C2String mName;
 
     friend struct Codec2Client;
 };
@@ -162,17 +160,17 @@
 
     typedef Codec2ConfigurableClient Configurable;
 
-    typedef Configurable Interface; // These two types may diverge in the future.
-
     struct Component;
 
+    struct Interface;
+
     struct InputSurface;
 
     struct InputSurfaceConnection;
 
     typedef Codec2Client Store;
 
-    std::string getInstanceName() const { return mInstanceName; }
+    std::string getServiceName() const { return mServiceName; }
 
     c2_status_t createComponent(
             const C2String& name,
@@ -195,7 +193,7 @@
     std::shared_ptr<C2ParamReflector> getParamReflector();
 
     static std::shared_ptr<Codec2Client> CreateFromService(
-            const char* instanceName,
+            const char* serviceName,
             bool waitForService = true);
 
     // Try to create a component with a given name from all known
@@ -218,10 +216,10 @@
     static std::shared_ptr<InputSurface> CreateInputSurface();
 
     // base cannot be null.
-    Codec2Client(const sp<Base>& base, std::string instanceName);
+    Codec2Client(const sp<Base>& base, std::string serviceName);
 
 protected:
-    Base* base() const;
+    sp<Base> mBase;
 
     // Finds the first store where the predicate returns OK, and returns the last
     // predicate result. Uses key to remember the last store found, and if cached,
@@ -232,7 +230,7 @@
 
     mutable std::mutex mMutex;
     mutable bool mListed;
-    std::string mInstanceName;
+    std::string mServiceName;
     mutable std::vector<C2Component::Traits> mTraitsList;
     mutable std::vector<std::unique_ptr<std::vector<std::string>>>
             mAliasesBuffer;
@@ -241,6 +239,16 @@
             mHostPoolManager;
 };
 
+struct Codec2Client::Interface : public Codec2Client::Configurable {
+
+    typedef ::android::hardware::media::c2::V1_0::IComponentInterface Base;
+
+    Interface(const sp<Base>& base);
+
+protected:
+    sp<Base> mBase;
+};
+
 struct Codec2Client::Listener {
 
     // This is called when the component produces some output.
@@ -277,28 +285,12 @@
     virtual void onInputBufferDone(
             const std::shared_ptr<C2Buffer>& buffer) = 0;
 
-    // This structure is used for transporting onFramesRendered() event to the
-    // client in the case where the output buffers are obtained from a
-    // bufferqueue.
-    struct RenderedFrame {
-        // The id of the bufferqueue.
-        uint64_t bufferQueueId;
-        // The slot of the buffer inside the bufferqueue.
-        int32_t slotId;
-        // The timestamp.
-        int64_t timestampNs;
-
-        RenderedFrame(uint64_t bufferQueueId, int32_t slotId,
-                      int64_t timestampNs)
-              : bufferQueueId(bufferQueueId),
-                slotId(slotId),
-                timestampNs(timestampNs) {}
-        RenderedFrame(const RenderedFrame&) = default;
-    };
-
-    // This is called when the component becomes aware of frames being rendered.
-    virtual void onFramesRendered(
-            const std::vector<RenderedFrame>& renderedFrames) = 0;
+    // This is called when the component becomes aware of a frame being
+    // rendered.
+    virtual void onFrameRendered(
+            uint64_t bufferQueueId,
+            int32_t slotId,
+            int64_t timestampNs) = 0;
 
     virtual ~Listener();
 
@@ -373,9 +365,15 @@
             const QueueBufferInput& input,
             QueueBufferOutput* output);
 
+    // Connect to a given InputSurface.
+    c2_status_t connectToInputSurface(
+            const std::shared_ptr<InputSurface>& inputSurface,
+            std::shared_ptr<InputSurfaceConnection>* connection);
+
     c2_status_t connectToOmxInputSurface(
             const sp<HGraphicBufferProducer>& producer,
-            const sp<HGraphicBufferSource>& source);
+            const sp<HGraphicBufferSource>& source,
+            std::shared_ptr<InputSurfaceConnection>* connection);
 
     c2_status_t disconnectFromInputSurface();
 
@@ -385,7 +383,7 @@
     ~Component();
 
 protected:
-    Base* base() const;
+    sp<Base> mBase;
 
     // Mutex for mInputBuffers and mInputBufferCount.
     mutable std::mutex mInputBuffersMutex;
@@ -428,7 +426,7 @@
 
 };
 
-struct Codec2Client::InputSurface {
+struct Codec2Client::InputSurface : public Codec2Client::Configurable {
 public:
     typedef ::android::hardware::media::c2::V1_0::IInputSurface Base;
 
@@ -439,22 +437,15 @@
 
     typedef ::android::IGraphicBufferProducer IGraphicBufferProducer;
 
-    c2_status_t connectToComponent(
-            const std::shared_ptr<Component>& component,
-            std::shared_ptr<Connection>* connection);
-
-    std::shared_ptr<Configurable> getConfigurable() const;
-
-    const sp<IGraphicBufferProducer>& getGraphicBufferProducer() const;
+    sp<IGraphicBufferProducer> getGraphicBufferProducer() const;
 
     // Return the underlying IInputSurface.
-    const sp<Base>& getHalInterface() const;
+    sp<Base> getHalInterface() const;
 
     // base cannot be null.
     InputSurface(const sp<Base>& base);
 
 protected:
-    Base* base() const;
     sp<Base> mBase;
 
     sp<IGraphicBufferProducer> mGraphicBufferProducer;
@@ -463,7 +454,7 @@
     friend struct Component;
 };
 
-struct Codec2Client::InputSurfaceConnection {
+struct Codec2Client::InputSurfaceConnection : public Codec2Client::Configurable {
 
     typedef ::android::hardware::media::c2::V1_0::IInputSurfaceConnection Base;
 
@@ -473,7 +464,6 @@
     InputSurfaceConnection(const sp<Base>& base);
 
 protected:
-    Base* base() const;
     sp<Base> mBase;
 
     friend struct Codec2Client::InputSurface;
@@ -481,5 +471,5 @@
 
 }  // namespace android
 
-#endif  // CODEC2_HIDL_CLIENT_H_
+#endif  // CODEC2_HIDL_CLIENT_H
 
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 852d6d6..10263de 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -143,8 +143,7 @@
         if (mConnection != nullptr) {
             return ALREADY_EXISTS;
         }
-        return toStatusT(mSurface->connectToComponent(comp, &mConnection),
-                         C2_OPERATION_InputSurface_connectToComponent);
+        return toStatusT(comp->connectToInputSurface(mSurface, &mConnection));
     }
 
     void disconnect() override {
@@ -162,7 +161,7 @@
     status_t signalEndOfInputStream() override {
         C2InputSurfaceEosTuning eos(true);
         std::vector<std::unique_ptr<C2SettingResult>> failures;
-        c2_status_t err = mSurface->getConfigurable()->config({&eos}, C2_MAY_BLOCK, &failures);
+        c2_status_t err = mSurface->config({&eos}, C2_MAY_BLOCK, &failures);
         if (err != C2_OK) {
             return UNKNOWN_ERROR;
         }
@@ -495,10 +494,13 @@
         codec->mCallback->onError(DEAD_OBJECT, ACTION_CODE_FATAL);
     }
 
-    virtual void onFramesRendered(
-            const std::vector<RenderedFrame>& renderedFrames) override {
-        // TODO
-        (void)renderedFrames;
+    virtual void onFrameRendered(uint64_t bufferQueueId,
+                                 int32_t slotId,
+                                 int64_t timestampNs) override {
+        // TODO: implement
+        (void)bufferQueueId;
+        (void)slotId;
+        (void)timestampNs;
     }
 
     virtual void onInputBufferDone(
@@ -599,7 +601,7 @@
     // set up preferred component store to access vendor store parameters
     client = Codec2Client::CreateFromService("default", false);
     if (client) {
-        ALOGI("setting up '%s' as default (vendor) store", client->getInstanceName().c_str());
+        ALOGI("setting up '%s' as default (vendor) store", client->getServiceName().c_str());
         SetPreferredCodec2ComponentStore(
                 std::make_shared<Codec2ClientInterfaceWrapper>(client));
     }
@@ -956,16 +958,18 @@
     std::shared_ptr<PersistentSurface> persistentSurface(CreateInputSurface());
 
     if (persistentSurface->getHidlTarget()) {
-        sp<IInputSurface> inputSurface = IInputSurface::castFrom(
+        sp<IInputSurface> hidlInputSurface = IInputSurface::castFrom(
                 persistentSurface->getHidlTarget());
-        if (!inputSurface) {
+        if (!hidlInputSurface) {
             ALOGE("Corrupted input surface");
             mCallback->onInputSurfaceCreationFailed(UNKNOWN_ERROR);
             return;
         }
+        std::shared_ptr<Codec2Client::InputSurface> inputSurface =
+                std::make_shared<Codec2Client::InputSurface>(hidlInputSurface);
         err = setupInputSurface(std::make_shared<C2InputSurfaceWrapper>(
-                std::make_shared<Codec2Client::InputSurface>(inputSurface)));
-        bufferProducer = new H2BGraphicBufferProducer(inputSurface);
+                inputSurface));
+        bufferProducer = inputSurface->getGraphicBufferProducer();
     } else {
         int32_t width = 0;
         (void)outputFormat->findInt32("width", &width);
@@ -1020,7 +1024,7 @@
         ALOGD("ISConfig: no configuration");
     }
 
-    return surface->start();
+    return OK;
 }
 
 void CCodec::initiateSetInputSurface(const sp<PersistentSurface> &surface) {
@@ -1107,12 +1111,20 @@
     }
     sp<AMessage> inputFormat;
     sp<AMessage> outputFormat;
+    status_t err2 = OK;
     {
         Mutexed<Config>::Locked config(mConfig);
         inputFormat = config->mInputFormat;
         outputFormat = config->mOutputFormat;
+        if (config->mInputSurface) {
+            err2 = config->mInputSurface->start();
+        }
     }
-    status_t err2 = mChannel->start(inputFormat, outputFormat);
+    if (err2 != OK) {
+        mCallback->onError(err2, ACTION_CODE_FATAL);
+        return;
+    }
+    err2 = mChannel->start(inputFormat, outputFormat);
     if (err2 != OK) {
         mCallback->onError(err2, ACTION_CODE_FATAL);
         return;
@@ -1187,6 +1199,13 @@
     }
 
     {
+        Mutexed<Config>::Locked config(mConfig);
+        if (config->mInputSurface) {
+            config->mInputSurface->disconnect();
+            config->mInputSurface = nullptr;
+        }
+    }
+    {
         Mutexed<State>::Locked state(mState);
         if (state->get() == STOPPING) {
             state->set(ALLOCATED);
@@ -1196,6 +1215,7 @@
 }
 
 void CCodec::initiateRelease(bool sendCallback /* = true */) {
+    bool clearInputSurfaceIfNeeded = false;
     {
         Mutexed<State>::Locked state(mState);
         if (state->get() == RELEASED || state->get() == RELEASING) {
@@ -1217,9 +1237,23 @@
             }
             return;
         }
+        if (state->get() == STARTING
+                || state->get() == RUNNING
+                || state->get() == STOPPING) {
+            // Input surface may have been started, so clean up is needed.
+            clearInputSurfaceIfNeeded = true;
+        }
         state->set(RELEASING);
     }
 
+    if (clearInputSurfaceIfNeeded) {
+        Mutexed<Config>::Locked config(mConfig);
+        if (config->mInputSurface) {
+            config->mInputSurface->disconnect();
+            config->mInputSurface = nullptr;
+        }
+    }
+
     mChannel->stop();
     // thiz holds strong ref to this while the thread is running.
     sp<CCodec> thiz(this);
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index b529cbc..9616e47 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -128,7 +128,9 @@
      * and released successfully.
      */
     virtual bool releaseBuffer(
-            const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) = 0;
+            const sp<MediaCodecBuffer> &buffer,
+            std::shared_ptr<C2Buffer> *c2buffer,
+            bool release) = 0;
 
     /**
      * Release the buffer that is no longer used by the codec process. Return
@@ -455,13 +457,18 @@
      * \return  true  if the buffer is successfully released from a slot
      *          false otherwise
      */
-    bool releaseSlot(const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
+    bool releaseSlot(
+            const sp<MediaCodecBuffer> &buffer,
+            std::shared_ptr<C2Buffer> *c2buffer,
+            bool release) {
         sp<Codec2Buffer> clientBuffer;
         size_t index = mBuffers.size();
         for (size_t i = 0; i < mBuffers.size(); ++i) {
             if (mBuffers[i].clientBuffer == buffer) {
                 clientBuffer = mBuffers[i].clientBuffer;
-                mBuffers[i].clientBuffer.clear();
+                if (release) {
+                    mBuffers[i].clientBuffer.clear();
+                }
                 index = i;
                 break;
             }
@@ -470,8 +477,11 @@
             ALOGV("[%s] %s: No matching buffer found", mName, __func__);
             return false;
         }
-        std::shared_ptr<C2Buffer> result = clientBuffer->asC2Buffer();
-        mBuffers[index].compBuffer = result;
+        std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
+        if (!result) {
+            result = clientBuffer->asC2Buffer();
+            mBuffers[index].compBuffer = result;
+        }
         if (c2buffer) {
             *c2buffer = result;
         }
@@ -485,8 +495,8 @@
             if (!compBuffer || compBuffer != c2buffer) {
                 continue;
             }
-            mBuffers[i].clientBuffer = nullptr;
             mBuffers[i].compBuffer.reset();
+            ALOGV("[%s] codec released buffer #%zu", mName, i);
             return true;
         }
         ALOGV("[%s] codec released an unknown buffer", mName);
@@ -597,7 +607,10 @@
      * \return  true  if the buffer is successfully returned
      *          false otherwise
      */
-    bool returnBuffer(const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
+    bool returnBuffer(
+            const sp<MediaCodecBuffer> &buffer,
+            std::shared_ptr<C2Buffer> *c2buffer,
+            bool release) {
         sp<Codec2Buffer> clientBuffer;
         size_t index = mBuffers.size();
         for (size_t i = 0; i < mBuffers.size(); ++i) {
@@ -606,7 +619,9 @@
                     ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu", mName, i);
                 }
                 clientBuffer = mBuffers[i].clientBuffer;
-                mBuffers[i].ownedByClient = false;
+                if (release) {
+                    mBuffers[i].ownedByClient = false;
+                }
                 index = i;
                 break;
             }
@@ -616,8 +631,11 @@
             return false;
         }
         ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
-        std::shared_ptr<C2Buffer> result = clientBuffer->asC2Buffer();
-        mBuffers[index].compBuffer = result;
+        std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
+        if (!result) {
+            result = clientBuffer->asC2Buffer();
+            mBuffers[index].compBuffer = result;
+        }
         if (c2buffer) {
             *c2buffer = result;
         }
@@ -636,9 +654,9 @@
                     // This should not happen.
                     ALOGD("[%s] codec released a buffer owned by client "
                           "(index %zu)", mName, i);
-                    mBuffers[i].ownedByClient = false;
                 }
                 mBuffers[i].compBuffer.reset();
+                ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
                 return true;
             }
         }
@@ -723,8 +741,10 @@
     }
 
     bool releaseBuffer(
-            const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override {
-        return mImpl.returnBuffer(buffer, c2buffer);
+            const sp<MediaCodecBuffer> &buffer,
+            std::shared_ptr<C2Buffer> *c2buffer,
+            bool release) override {
+        return mImpl.returnBuffer(buffer, c2buffer, release);
     }
 
     bool expireComponentBuffer(
@@ -765,8 +785,10 @@
     }
 
     bool releaseBuffer(
-            const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override {
-        return mImpl.releaseSlot(buffer, c2buffer);
+            const sp<MediaCodecBuffer> &buffer,
+            std::shared_ptr<C2Buffer> *c2buffer,
+            bool release) override {
+        return mImpl.releaseSlot(buffer, c2buffer, release);
     }
 
     bool expireComponentBuffer(
@@ -801,7 +823,7 @@
         return std::move(array);
     }
 
-    virtual sp<Codec2Buffer> alloc(size_t size) const {
+    virtual sp<Codec2Buffer> alloc(size_t size) {
         C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
         std::shared_ptr<C2LinearBlock> block;
 
@@ -850,11 +872,12 @@
     ~EncryptedLinearInputBuffers() override {
     }
 
-    sp<Codec2Buffer> alloc(size_t size) const override {
+    sp<Codec2Buffer> alloc(size_t size) override {
         sp<IMemory> memory;
-        for (const Entry &entry : mMemoryVector) {
-            if (entry.block.expired()) {
-                memory = entry.memory;
+        size_t slot = 0;
+        for (; slot < mMemoryVector.size(); ++slot) {
+            if (mMemoryVector[slot].block.expired()) {
+                memory = mMemoryVector[slot].memory;
                 break;
             }
         }
@@ -864,10 +887,11 @@
 
         std::shared_ptr<C2LinearBlock> block;
         c2_status_t err = mPool->fetchLinearBlock(size, mUsage, &block);
-        if (err != C2_OK) {
+        if (err != C2_OK || block == nullptr) {
             return nullptr;
         }
 
+        mMemoryVector[slot].block = block;
         return new EncryptedLinearBlockBuffer(mFormat, block, memory, mHeapSeqNum);
     }
 
@@ -907,8 +931,10 @@
     }
 
     bool releaseBuffer(
-            const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override {
-        return mImpl.releaseSlot(buffer, c2buffer);
+            const sp<MediaCodecBuffer> &buffer,
+            std::shared_ptr<C2Buffer> *c2buffer,
+            bool release) override {
+        return mImpl.releaseSlot(buffer, c2buffer, release);
     }
 
     bool expireComponentBuffer(
@@ -971,14 +997,17 @@
     }
 
     bool releaseBuffer(
-            const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override {
-        return mImpl.releaseSlot(buffer, c2buffer);
+            const sp<MediaCodecBuffer> &buffer,
+            std::shared_ptr<C2Buffer> *c2buffer,
+            bool release) override {
+        return mImpl.releaseSlot(buffer, c2buffer, release);
     }
 
     bool expireComponentBuffer(
             const std::shared_ptr<C2Buffer> &c2buffer) override {
         return mImpl.expireComponentBuffer(c2buffer);
     }
+
     void flush() override {
         // This is no-op by default unless we're in array mode where we need to keep
         // track of the flushed work.
@@ -1016,7 +1045,7 @@
     }
 
     bool releaseBuffer(
-            const sp<MediaCodecBuffer> &, std::shared_ptr<C2Buffer> *) override {
+            const sp<MediaCodecBuffer> &, std::shared_ptr<C2Buffer> *, bool) override {
         return false;
     }
 
@@ -1111,7 +1140,7 @@
 
     bool releaseBuffer(
             const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override {
-        return mImpl.returnBuffer(buffer, c2buffer);
+        return mImpl.returnBuffer(buffer, c2buffer, true);
     }
 
     void flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) override {
@@ -1171,6 +1200,9 @@
             size_t *index,
             sp<MediaCodecBuffer> *clientBuffer) override {
         sp<Codec2Buffer> newBuffer = wrap(buffer);
+        if (newBuffer == nullptr) {
+            return NO_MEMORY;
+        }
         newBuffer->setFormat(mFormat);
         *index = mImpl.assignSlot(newBuffer);
         *clientBuffer = newBuffer;
@@ -1190,8 +1222,9 @@
     }
 
     bool releaseBuffer(
-            const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override {
-        return mImpl.releaseSlot(buffer, c2buffer);
+            const sp<MediaCodecBuffer> &buffer,
+            std::shared_ptr<C2Buffer> *c2buffer) override {
+        return mImpl.releaseSlot(buffer, c2buffer, true);
     }
 
     void flush(
@@ -1263,6 +1296,10 @@
             return nullptr;
         }
         sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
+        if (clientBuffer == nullptr) {
+            ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
+            return nullptr;
+        }
         submit(clientBuffer);
         return clientBuffer;
     }
@@ -1303,6 +1340,10 @@
                     [lbp = mLocalBufferPool](size_t capacity) {
                         return lbp->newBuffer(capacity);
                     });
+            if (c2buffer == nullptr) {
+                ALOGD("[%s] ConstGraphicBlockBuffer::AllocateEmpty failed", mName);
+                return nullptr;
+            }
             c2buffer->setRange(0, 0);
             return c2buffer;
         } else {
@@ -1478,6 +1519,11 @@
     mKey = C2Config::ORDINAL;
 }
 
+void CCodecBufferChannel::ReorderStash::flush() {
+    mPending.clear();
+    mStash.clear();
+}
+
 void CCodecBufferChannel::ReorderStash::setDepth(uint32_t depth) {
     mPending.splice(mPending.end(), mStash);
     mDepth = depth;
@@ -1615,7 +1661,7 @@
     if (buffer->size() > 0u) {
         Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers);
         std::shared_ptr<C2Buffer> c2buffer;
-        if (!(*buffers)->releaseBuffer(buffer, &c2buffer)) {
+        if (!(*buffers)->releaseBuffer(buffer, &c2buffer, false)) {
             return -ENOENT;
         }
         work->input.buffers.push_back(c2buffer);
@@ -1645,6 +1691,7 @@
         work->input.ordinal.customOrdinal = timeUs;
         work->input.buffers.clear();
         work->input.flags = C2FrameData::FLAG_END_OF_STREAM;
+        work->worklets.emplace_back(new C2Worklet);
 
         items.clear();
         items.push_back(std::move(work));
@@ -1652,6 +1699,10 @@
     }
     if (err == C2_OK) {
         mCCodecCallback->onWorkQueued(eos);
+
+        Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers);
+        bool released = (*buffers)->releaseBuffer(buffer, nullptr, true);
+        ALOGV("[%s] queueInputBuffer: buffer %sreleased", mName, released ? "" : "not ");
     }
 
     feedInputBufferIfAvailableInternal();
@@ -1980,7 +2031,7 @@
     bool released = false;
     {
         Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers);
-        if (*buffers && (*buffers)->releaseBuffer(buffer, nullptr)) {
+        if (*buffers && (*buffers)->releaseBuffer(buffer, nullptr, true)) {
             buffers.unlock();
             released = true;
             mAvailablePipelineCapacity.freeInputSlots(1, "discardBuffer");
@@ -2445,7 +2496,6 @@
     mSync.stop();
     mFirstValidFrameIndex = mFrameIndex.load(std::memory_order_relaxed);
     if (mInputSurface != nullptr) {
-        mInputSurface->disconnect();
         mInputSurface.reset();
     }
 }
@@ -2481,6 +2531,7 @@
         Mutexed<std::unique_ptr<OutputBuffers>>::Locked buffers(mOutputBuffers);
         (*buffers)->flush(flushedWork);
     }
+    mReorderStash.lock()->flush();
 }
 
 void CCodecBufferChannel::onWorkDone(
@@ -2708,6 +2759,9 @@
         status_t err = (*buffers)->registerBuffer(entry.buffer, &index, &outBuffer);
         if (err != OK) {
             if (err != WOULD_BLOCK) {
+                if (!(*buffers)->isArrayMode()) {
+                    *buffers = (*buffers)->toArrayMode(mNumOutputSlots);
+                }
                 OutputBuffersArray *array = (OutputBuffersArray *)buffers->get();
                 array->realloc(entry.buffer);
                 mCCodecCallback->onOutputBuffersChanged();
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.h b/media/codec2/sfplugin/CCodecBufferChannel.h
index fd806b7..ebc1491 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.h
+++ b/media/codec2/sfplugin/CCodecBufferChannel.h
@@ -359,6 +359,7 @@
         ReorderStash();
 
         void clear();
+        void flush();
         void setDepth(uint32_t depth);
         void setKey(C2Config::ordinal_key_t key);
         bool pop(Entry *entry);
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index 597e8f3..2dec42e 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -451,6 +451,9 @@
     }
 
     bool setBackBuffer(const sp<ABuffer> &backBuffer) {
+        if (backBuffer == nullptr) {
+            return false;
+        }
         if (backBuffer->capacity() < mBackBufferSize) {
             return false;
         }
diff --git a/media/codec2/sfplugin/Codec2InfoBuilder.cpp b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
index a8cc62d..5f0dd0b 100644
--- a/media/codec2/sfplugin/Codec2InfoBuilder.cpp
+++ b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
@@ -44,6 +44,7 @@
 #include <cutils/native_handle.h>
 #include <media/omx/1.0/WOmxNode.h>
 #include <media/stagefright/MediaCodecConstants.h>
+#include <media/stagefright/foundation/ALookup.h>
 #include <media/stagefright/foundation/MediaDefs.h>
 #include <media/stagefright/omx/OMXUtils.h>
 #include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
@@ -299,7 +300,6 @@
         // OMX components don't have aliases
         for (const MediaCodecsXmlParser::Type &type : properties.typeMap) {
             const std::string &mediaType = type.first;
-
             std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
                     info->addMediaType(mediaType.c_str());
             const MediaCodecsXmlParser::AttributeMap &attrMap = type.second;
@@ -376,7 +376,7 @@
     }
 
     bool surfaceTest(Codec2Client::CreateInputSurface());
-    if (option == 0 || !surfaceTest) {
+    if (option == 0 || (option != 4 && !surfaceTest)) {
         buildOmxInfo(parser, writer);
     }
 
diff --git a/media/codec2/sfplugin/utils/Android.bp b/media/codec2/sfplugin/utils/Android.bp
index eb6c3e9..8c8f025 100644
--- a/media/codec2/sfplugin/utils/Android.bp
+++ b/media/codec2/sfplugin/utils/Android.bp
@@ -26,6 +26,10 @@
         "libutils",
     ],
 
+    static_libs: [
+        "libyuv_static",
+    ],
+
     sanitize: {
         cfi: true,
         misc_undefined: [
diff --git a/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp b/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
index 84d22a3..6b8663f 100644
--- a/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
+++ b/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
@@ -18,6 +18,8 @@
 #define LOG_TAG "Codec2BufferUtils"
 #include <utils/Log.h>
 
+#include <libyuv.h>
+
 #include <list>
 #include <mutex>
 
@@ -62,14 +64,10 @@
  */
 template<bool ToMediaImage, typename View, typename ImagePixel>
 static status_t _ImageCopy(View &view, const MediaImage2 *img, ImagePixel *imgBase) {
-    // TODO: more efficient copying --- e.g. one row at a time, copying
-    //       interleaved planes together, etc.
+    // TODO: more efficient copying --- e.g. copy interleaved planes together, etc.
     const C2PlanarLayout &layout = view.layout();
     const size_t bpp = divUp(img->mBitDepthAllocated, 8u);
-    if (view.width() != img->mWidth
-            || view.height() != img->mHeight) {
-        return BAD_VALUE;
-    }
+
     for (uint32_t i = 0; i < layout.numPlanes; ++i) {
         typename std::conditional<ToMediaImage, uint8_t, const uint8_t>::type *imgRow =
             imgBase + img->mPlane[i].mOffset;
@@ -120,10 +118,72 @@
 }  // namespace
 
 status_t ImageCopy(uint8_t *imgBase, const MediaImage2 *img, const C2GraphicView &view) {
+    if (view.width() != img->mWidth || view.height() != img->mHeight) {
+        return BAD_VALUE;
+    }
+    if ((IsNV12(view) && IsI420(img)) || (IsI420(view) && IsNV12(img))) {
+        // Take shortcuts to use libyuv functions between NV12 and I420 conversion.
+        const uint8_t* src_y = view.data()[0];
+        const uint8_t* src_u = view.data()[1];
+        const uint8_t* src_v = view.data()[2];
+        int32_t src_stride_y = view.layout().planes[0].rowInc;
+        int32_t src_stride_u = view.layout().planes[1].rowInc;
+        int32_t src_stride_v = view.layout().planes[2].rowInc;
+        uint8_t* dst_y = imgBase + img->mPlane[0].mOffset;
+        uint8_t* dst_u = imgBase + img->mPlane[1].mOffset;
+        uint8_t* dst_v = imgBase + img->mPlane[2].mOffset;
+        int32_t dst_stride_y = img->mPlane[0].mRowInc;
+        int32_t dst_stride_u = img->mPlane[1].mRowInc;
+        int32_t dst_stride_v = img->mPlane[2].mRowInc;
+        if (IsNV12(view) && IsI420(img)) {
+            if (!libyuv::NV12ToI420(src_y, src_stride_y, src_u, src_stride_u, dst_y, dst_stride_y,
+                                    dst_u, dst_stride_u, dst_v, dst_stride_v, view.width(),
+                                    view.height())) {
+                return OK;
+            }
+        } else {
+            if (!libyuv::I420ToNV12(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v,
+                                    dst_y, dst_stride_y, dst_u, dst_stride_u, view.width(),
+                                    view.height())) {
+                return OK;
+            }
+        }
+    }
     return _ImageCopy<true>(view, img, imgBase);
 }
 
 status_t ImageCopy(C2GraphicView &view, const uint8_t *imgBase, const MediaImage2 *img) {
+    if (view.width() != img->mWidth || view.height() != img->mHeight) {
+        return BAD_VALUE;
+    }
+    if ((IsNV12(img) && IsI420(view)) || (IsI420(img) && IsNV12(view))) {
+        // Take shortcuts to use libyuv functions between NV12 and I420 conversion.
+        const uint8_t* src_y = imgBase + img->mPlane[0].mOffset;
+        const uint8_t* src_u = imgBase + img->mPlane[1].mOffset;
+        const uint8_t* src_v = imgBase + img->mPlane[2].mOffset;
+        int32_t src_stride_y = img->mPlane[0].mRowInc;
+        int32_t src_stride_u = img->mPlane[1].mRowInc;
+        int32_t src_stride_v = img->mPlane[2].mRowInc;
+        uint8_t* dst_y = view.data()[0];
+        uint8_t* dst_u = view.data()[1];
+        uint8_t* dst_v = view.data()[2];
+        int32_t dst_stride_y = view.layout().planes[0].rowInc;
+        int32_t dst_stride_u = view.layout().planes[1].rowInc;
+        int32_t dst_stride_v = view.layout().planes[2].rowInc;
+        if (IsNV12(img) && IsI420(view)) {
+            if (!libyuv::NV12ToI420(src_y, src_stride_y, src_u, src_stride_u, dst_y, dst_stride_y,
+                                    dst_u, dst_stride_u, dst_v, dst_stride_v, view.width(),
+                                    view.height())) {
+                return OK;
+            }
+        } else {
+            if (!libyuv::I420ToNV12(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v,
+                                    dst_y, dst_stride_y, dst_u, dst_stride_u, view.width(),
+                                    view.height())) {
+                return OK;
+            }
+        }
+    }
     return _ImageCopy<false>(view, img, imgBase);
 }
 
@@ -151,6 +211,65 @@
             && layout.planes[layout.PLANE_V].rowSampling == 2);
 }
 
+bool IsNV12(const C2GraphicView &view) {
+    if (!IsYUV420(view)) {
+        return false;
+    }
+    const C2PlanarLayout &layout = view.layout();
+    return (layout.rootPlanes == 2
+            && layout.planes[layout.PLANE_U].colInc == 2
+            && layout.planes[layout.PLANE_U].rootIx == layout.PLANE_U
+            && layout.planes[layout.PLANE_U].offset == 0
+            && layout.planes[layout.PLANE_V].colInc == 2
+            && layout.planes[layout.PLANE_V].rootIx == layout.PLANE_U
+            && layout.planes[layout.PLANE_V].offset == 1);
+}
+
+bool IsI420(const C2GraphicView &view) {
+    if (!IsYUV420(view)) {
+        return false;
+    }
+    const C2PlanarLayout &layout = view.layout();
+    return (layout.rootPlanes == 3
+            && layout.planes[layout.PLANE_U].colInc == 1
+            && layout.planes[layout.PLANE_U].rootIx == layout.PLANE_U
+            && layout.planes[layout.PLANE_U].offset == 0
+            && layout.planes[layout.PLANE_V].colInc == 1
+            && layout.planes[layout.PLANE_V].rootIx == layout.PLANE_V
+            && layout.planes[layout.PLANE_V].offset == 0);
+}
+
+bool IsYUV420(const MediaImage2 *img) {
+    return (img->mType == MediaImage2::MEDIA_IMAGE_TYPE_YUV
+            && img->mNumPlanes == 3
+            && img->mBitDepth == 8
+            && img->mBitDepthAllocated == 8
+            && img->mPlane[0].mHorizSubsampling == 1
+            && img->mPlane[0].mVertSubsampling == 1
+            && img->mPlane[1].mHorizSubsampling == 2
+            && img->mPlane[1].mVertSubsampling == 2
+            && img->mPlane[2].mHorizSubsampling == 2
+            && img->mPlane[2].mVertSubsampling == 2);
+}
+
+bool IsNV12(const MediaImage2 *img) {
+    if (!IsYUV420(img)) {
+        return false;
+    }
+    return (img->mPlane[1].mColInc == 2
+            && img->mPlane[2].mColInc == 2
+            && (img->mPlane[2].mOffset - img->mPlane[1].mOffset == 1));
+}
+
+bool IsI420(const MediaImage2 *img) {
+    if (!IsYUV420(img)) {
+        return false;
+    }
+    return (img->mPlane[1].mColInc == 1
+            && img->mPlane[2].mColInc == 1
+            && img->mPlane[2].mOffset > img->mPlane[1].mOffset);
+}
+
 MediaImage2 CreateYUV420PlanarMediaImage2(
         uint32_t width, uint32_t height, uint32_t stride, uint32_t vstride) {
     return MediaImage2 {
diff --git a/media/codec2/sfplugin/utils/Codec2BufferUtils.h b/media/codec2/sfplugin/utils/Codec2BufferUtils.h
index eaf6776..afadf00 100644
--- a/media/codec2/sfplugin/utils/Codec2BufferUtils.h
+++ b/media/codec2/sfplugin/utils/Codec2BufferUtils.h
@@ -91,6 +91,31 @@
 bool IsYUV420(const C2GraphicView &view);
 
 /**
+ * Returns true iff a view has a NV12 layout.
+ */
+bool IsNV12(const C2GraphicView &view);
+
+/**
+ * Returns true iff a view has a I420 layout.
+ */
+bool IsI420(const C2GraphicView &view);
+
+/**
+ * Returns true iff a MediaImage2 has a YUV 420 888 layout.
+ */
+bool IsYUV420(const MediaImage2 *img);
+
+/**
+ * Returns true iff a MediaImage2 has a NV12 layout.
+ */
+bool IsNV12(const MediaImage2 *img);
+
+/**
+ * Returns true iff a MediaImage2 has a I420 layout.
+ */
+bool IsI420(const MediaImage2 *img);
+
+/**
  * A raw memory block to use for internal buffers.
  *
  * TODO: replace this with C2LinearBlocks from a private C2BlockPool
diff --git a/media/codec2/vndk/platform/C2BqBuffer.cpp b/media/codec2/vndk/platform/C2BqBuffer.cpp
index 6e71b98..7bf3d64 100644
--- a/media/codec2/vndk/platform/C2BqBuffer.cpp
+++ b/media/codec2/vndk/platform/C2BqBuffer.cpp
@@ -192,7 +192,7 @@
         int slot;
         ALOGV("tries to dequeue buffer");
         Return<void> transStatus = mProducer->dequeueBuffer(
-                width, height, pixelFormat, androidUsage.asGrallocUsage(), true,
+                width, height, pixelFormat, androidUsage.asGrallocUsage(), false,
                 [&status, &slot, &fence](
                         int32_t tStatus, int32_t tSlot, hidl_handle const& tFence,
                         HGraphicBufferProducer::FrameEventHistoryDelta const& tTs) {
diff --git a/media/extractors/flac/FLACExtractor.cpp b/media/extractors/flac/FLACExtractor.cpp
index 84fbcee..8854631 100644
--- a/media/extractors/flac/FLACExtractor.cpp
+++ b/media/extractors/flac/FLACExtractor.cpp
@@ -581,6 +581,7 @@
     CHECK(mGroup == NULL);
     mGroup = group;
     mMaxBufferSize = getMaxBlockSize() * getChannels() * getOutputSampleSize();
+    AMediaFormat_setInt32(mTrackMetadata, AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, mMaxBufferSize);
     mGroup->add_buffer(mMaxBufferSize);
 }
 
@@ -667,7 +668,7 @@
     : mDataSource(dataSource),
       mTrackMetadata(trackMetadata),
       mOutputFloat(outputFloat),
-      mParser(new FLACParser(mDataSource, outputFloat)),
+      mParser(new FLACParser(mDataSource, outputFloat, 0, mTrackMetadata)),
       mInitCheck(mParser->initCheck()),
       mStarted(false)
 {
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 237f9c8..ac54116 100755
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -1635,9 +1635,8 @@
         case FOURCC(".mp3"):
         case 0x6D730055: // "ms U" mp3 audio
         {
-            if (mIsQT && chunk_type == FOURCC("mp4a")
-                    && depth >= 1 && mPath[depth - 1] == FOURCC("wave")) {
-                // Ignore mp4a embedded in QT wave atom
+            if (mIsQT && depth >= 1 && mPath[depth - 1] == FOURCC("wave")) {
+                // Ignore all atoms embedded in QT wave atom
                 *offset += chunk_size;
                 break;
             }
@@ -1666,7 +1665,7 @@
             off64_t stop_offset = *offset + chunk_size;
             *offset = data_offset + sizeof(buffer);
 
-            if (mIsQT && chunk_type == FOURCC("mp4a")) {
+            if (mIsQT) {
                 if (version == 1) {
                     if (mDataSource->readAt(*offset, buffer, 16) < 16) {
                         return ERROR_IO;
@@ -1995,6 +1994,13 @@
 
             *offset += chunk_size;
 
+            if (depth >= 1 && mPath[depth - 1] != FOURCC("stbl")) {
+                char chunk[5];
+                MakeFourCCString(mPath[depth - 1], chunk);
+                ALOGW("stts's parent box (%s) is not stbl, skip it.", chunk);
+                break;
+            }
+
             status_t err =
                 mLastTrack->sampleTable->setTimeToSampleParams(
                         data_offset, chunk_data_size);
diff --git a/media/extractors/mpeg2/Android.bp b/media/extractors/mpeg2/Android.bp
index 2a94671..0f0c72c 100644
--- a/media/extractors/mpeg2/Android.bp
+++ b/media/extractors/mpeg2/Android.bp
@@ -24,6 +24,8 @@
 
     header_libs: [
         "libbase_headers",
+        "libstagefright_headers",
+        "libmedia_headers",
     ],
 
     static_libs: [
@@ -31,7 +33,7 @@
         "libstagefright_foundation_without_imemory",
         "libstagefright_mpeg2support",
         "libutils",
-        "libstagefright",
+        "libstagefright_mpeg2extractor",
         "libstagefright_esds",
     ],
 
diff --git a/media/extractors/ogg/OggExtractor.cpp b/media/extractors/ogg/OggExtractor.cpp
index 596c1c8..ba40690 100644
--- a/media/extractors/ogg/OggExtractor.cpp
+++ b/media/extractors/ogg/OggExtractor.cpp
@@ -983,7 +983,7 @@
         size_t denom = numerator - kMaxNumTOCEntries;
 
         size_t accum = 0;
-        for (ssize_t i = mTableOfContents.size() - 1; i >= 0; --i) {
+        for (ssize_t i = mTableOfContents.size(); i > 0; --i) {
             accum += denom;
             if (accum >= numerator) {
                 mTableOfContents.removeAt(i);
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 3b03601..ec270f3 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -713,3 +713,7 @@
 aaudio_result_t AudioStreamInternal::joinThread(void** returnArg) {
     return AudioStream::joinThread(returnArg, calculateReasonableTimeout(getFramesPerBurst()));
 }
+
+bool AudioStreamInternal::isClockModelInControl() const {
+    return isActive() && mAudioEndpoint.isFreeRunning() && mClockModel.isRunning();
+}
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index 1c88f52..86c4698 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -144,6 +144,14 @@
      */
     bool isInService() const { return mInService; }
 
+    /**
+     * Is the service FIFO position currently controlled by the AAudio service or HAL,
+     * or set based on the Clock Model.
+     *
+     * @return true if the ClockModel is currently determining the FIFO position
+     */
+    bool isClockModelInControl() const;
+
     IsochronousClockModel    mClockModel;      // timing model for chasing the HAL
 
     AudioEndpoint            mAudioEndpoint;   // source for reads or sink for writes
diff --git a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
index 7dcb620..a6cc45b 100644
--- a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
@@ -210,17 +210,12 @@
 }
 
 int64_t AudioStreamInternalCapture::getFramesWritten() {
-    int64_t framesWrittenHardware;
-    if (isActive()) {
-        framesWrittenHardware = mClockModel.convertTimeToPosition(AudioClock::getNanoseconds());
-    } else {
-        framesWrittenHardware = mAudioEndpoint.getDataWriteCounter();
-    }
-    // Prevent retrograde motion.
+    const int64_t framesWrittenHardware = isClockModelInControl()
+            ? mClockModel.convertTimeToPosition(AudioClock::getNanoseconds())
+            : mAudioEndpoint.getDataWriteCounter();
+    // Add service offset and prevent retrograde motion.
     mLastFramesWritten = std::max(mLastFramesWritten,
                                   framesWrittenHardware + mFramesOffsetFromService);
-    //ALOGD("getFramesWritten() returns %lld",
-    //      (long long)mLastFramesWritten);
     return mLastFramesWritten;
 }
 
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index 6af8e7d..e1443d9 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -242,27 +242,17 @@
     return framesWritten;
 }
 
-int64_t AudioStreamInternalPlay::getFramesRead()
-{
-    int64_t framesReadHardware;
-    if (isActive()) {
-        framesReadHardware = mClockModel.convertTimeToPosition(AudioClock::getNanoseconds());
-    } else {
-        framesReadHardware = mAudioEndpoint.getDataReadCounter();
-    }
-    int64_t framesRead = framesReadHardware + mFramesOffsetFromService;
-    // Prevent retrograde motion.
-    if (framesRead < mLastFramesRead) {
-        framesRead = mLastFramesRead;
-    } else {
-        mLastFramesRead = framesRead;
-    }
-    return framesRead;
+int64_t AudioStreamInternalPlay::getFramesRead() {
+    const int64_t framesReadHardware = isClockModelInControl()
+            ? mClockModel.convertTimeToPosition(AudioClock::getNanoseconds())
+            : mAudioEndpoint.getDataReadCounter();
+    // Add service offset and prevent retrograde motion.
+    mLastFramesRead = std::max(mLastFramesRead, framesReadHardware + mFramesOffsetFromService);
+    return mLastFramesRead;
 }
 
-int64_t AudioStreamInternalPlay::getFramesWritten()
-{
-    int64_t framesWritten = mAudioEndpoint.getDataWriteCounter()
+int64_t AudioStreamInternalPlay::getFramesWritten() {
+    const int64_t framesWritten = mAudioEndpoint.getDataWriteCounter()
                                + mFramesOffsetFromService;
     return framesWritten;
 }
diff --git a/media/libaaudio/src/client/IsochronousClockModel.cpp b/media/libaaudio/src/client/IsochronousClockModel.cpp
index 95b52be..747d0e1 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.cpp
+++ b/media/libaaudio/src/client/IsochronousClockModel.cpp
@@ -60,10 +60,14 @@
     mState = STATE_STOPPED;
 }
 
-bool IsochronousClockModel::isStarting() {
+bool IsochronousClockModel::isStarting() const {
     return mState == STATE_STARTING;
 }
 
+bool IsochronousClockModel::isRunning() const {
+    return mState == STATE_RUNNING;
+}
+
 void IsochronousClockModel::processTimestamp(int64_t framePosition, int64_t nanoTime) {
 //    ALOGD("processTimestamp() - framePosition = %lld at nanoTime %llu",
 //         (long long)framePosition,
diff --git a/media/libaaudio/src/client/IsochronousClockModel.h b/media/libaaudio/src/client/IsochronousClockModel.h
index 7182376..46ca48e 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.h
+++ b/media/libaaudio/src/client/IsochronousClockModel.h
@@ -36,7 +36,15 @@
     void start(int64_t nanoTime);
     void stop(int64_t nanoTime);
 
-    bool isStarting();
+    /**
+     * @return true if the model is starting up
+     */
+    bool isStarting() const;
+
+    /**
+     * @return true if the model is running and producing valid results
+     */
+    bool isRunning() const;
 
     void processTimestamp(int64_t framePosition, int64_t nanoTime);
 
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index f550089..4a65fc9 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -326,16 +326,13 @@
     if (mAudioRecord.get() == nullptr) {
         return AAUDIO_ERROR_INVALID_STATE;
     }
-    // Get current position so we can detect when the track is recording.
-    status_t err = mAudioRecord->getPosition(&mPositionWhenStarting);
-    if (err != OK) {
-        return AAudioConvert_androidToAAudioResult(err);
-    }
 
-    // Enable callback before starting AudioTrack to avoid shutting
+    // Enable callback before starting AudioRecord to avoid shutting
     // down because of a race condition.
     mCallbackEnabled.store(true);
-    err = mAudioRecord->start();
+    mFramesWritten.reset32(); // service writes frames
+    mTimestampPosition.reset32();
+    status_t err = mAudioRecord->start(); // resets position to zero
     if (err != OK) {
         return AAudioConvert_androidToAAudioResult(err);
     } else {
@@ -349,12 +346,10 @@
         return AAUDIO_ERROR_INVALID_STATE;
     }
     setState(AAUDIO_STREAM_STATE_STOPPING);
-    incrementFramesWritten(getFramesRead() - getFramesWritten()); // TODO review
-    mTimestampPosition.set(getFramesRead());
+    mFramesWritten.catchUpTo(getFramesRead());
+    mTimestampPosition.catchUpTo(getFramesRead());
     mAudioRecord->stop();
     mCallbackEnabled.store(false);
-    mFramesWritten.reset32(); // service writes frames, service position reset on flush
-    mTimestampPosition.reset32();
     // Pass false to prevent errorCallback from being called after disconnect
     // when app has already requested a stop().
     return checkForDisconnectRequest(false);
@@ -368,10 +363,12 @@
     switch (getState()) {
     // TODO add better state visibility to AudioRecord
     case AAUDIO_STREAM_STATE_STARTING:
+        // When starting, the position will begin at zero and then go positive.
+        // The position can wrap but by that time the state will not be STARTING.
         err = mAudioRecord->getPosition(&position);
         if (err != OK) {
             result = AAudioConvert_androidToAAudioResult(err);
-        } else if (position != mPositionWhenStarting) {
+        } else if (position > 0) {
             setState(AAUDIO_STREAM_STATE_STARTED);
         }
         break;
@@ -504,12 +501,12 @@
     switch (getState()) {
         case AAUDIO_STREAM_STATE_STARTING:
         case AAUDIO_STREAM_STATE_STARTED:
-        case AAUDIO_STREAM_STATE_STOPPING:
             result = mAudioRecord->getPosition(&position);
             if (result == OK) {
                 mFramesWritten.update32(position);
             }
             break;
+        case AAUDIO_STREAM_STATE_STOPPING:
         default:
             break;
     }
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index c995e99..ff95aed 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -323,8 +323,8 @@
     }
 
     setState(AAUDIO_STREAM_STATE_STOPPING);
-    incrementFramesRead(getFramesWritten() - getFramesRead()); // TODO review
-    mTimestampPosition.set(getFramesWritten());
+    mFramesRead.catchUpTo(getFramesWritten());
+    mTimestampPosition.catchUpTo(getFramesWritten());
     mFramesRead.reset32(); // service reads frames, service position reset on stop
     mTimestampPosition.reset32();
     mAudioTrack->stop();
diff --git a/media/libaaudio/src/utility/MonotonicCounter.h b/media/libaaudio/src/utility/MonotonicCounter.h
index 5833eab..63add4e 100644
--- a/media/libaaudio/src/utility/MonotonicCounter.h
+++ b/media/libaaudio/src/utility/MonotonicCounter.h
@@ -41,10 +41,12 @@
     }
 
     /**
-     * set the current value of the counter
+     * advance the current value to match the counter
      */
-    void set(int64_t counter) {
-        mCounter64 = counter;
+    void catchUpTo(int64_t counter) {
+        if ((counter - mCounter64) > 0) {
+            mCounter64 = counter;
+        }
     }
 
     /**
diff --git a/media/libaaudio/tests/test_clock_model.cpp b/media/libaaudio/tests/test_clock_model.cpp
index 3c09025..7f7abbd 100644
--- a/media/libaaudio/tests/test_clock_model.cpp
+++ b/media/libaaudio/tests/test_clock_model.cpp
@@ -43,13 +43,47 @@
     }
 
     void TearDown() {
-
     }
 
     ~ClockModelTestFixture()  {
         // cleanup any pending stuff, but no exceptions allowed
     }
 
+    // Test processing of timestamps when the hardware may be slightly off from
+    // the expected sample rate.
+    void checkDriftingClock(double hardwareFramesPerSecond, int numLoops) {
+        const int64_t startTimeNanos = 500000000; // arbitrary
+        model.start(startTimeNanos);
+
+        const int64_t startPositionFrames = HW_FRAMES_PER_BURST; // hardware
+        // arbitrary time for first burst
+        const int64_t markerTime = startTimeNanos + NANOS_PER_MILLISECOND
+                + (200 * NANOS_PER_MICROSECOND);
+
+        // Should set initial marker.
+        model.processTimestamp(startPositionFrames, markerTime);
+        ASSERT_EQ(startPositionFrames, model.convertTimeToPosition(markerTime));
+
+        double elapsedTimeSeconds = startTimeNanos / (double) NANOS_PER_SECOND;
+        for (int i = 0; i < numLoops; i++) {
+            // Calculate random delay over several bursts.
+            const double timeDelaySeconds = 10.0 * drand48() * NANOS_PER_BURST / NANOS_PER_SECOND;
+            elapsedTimeSeconds += timeDelaySeconds;
+            const int64_t elapsedTimeNanos = (int64_t)(elapsedTimeSeconds * NANOS_PER_SECOND);
+            const int64_t currentTimeNanos = startTimeNanos + elapsedTimeNanos;
+            // Simulate DSP running at the specified rate.
+            const int64_t currentTimeFrames = startPositionFrames +
+                                        (int64_t)(hardwareFramesPerSecond * elapsedTimeSeconds);
+            const int64_t numBursts = currentTimeFrames / HW_FRAMES_PER_BURST;
+            const int64_t alignedPosition = startPositionFrames + (numBursts * HW_FRAMES_PER_BURST);
+
+            // Apply drifting timestamp.
+            model.processTimestamp(alignedPosition, currentTimeNanos);
+
+            ASSERT_EQ(alignedPosition, model.convertTimeToPosition(currentTimeNanos));
+        }
+    }
+
     IsochronousClockModel model;
 };
 
@@ -95,7 +129,6 @@
 }
 
 // timestamps moves the window if outside the bounds
-// TODO test nudging the window
 TEST_F(ClockModelTestFixture, clock_timestamp) {
     const int64_t startTime = 100000000;
     model.start(startTime);
@@ -113,3 +146,21 @@
     // convertPositionToTime rounds up
     EXPECT_EQ(markerTime + NANOS_PER_BURST, model.convertPositionToTime(position + 17));
 }
+
+#define NUM_LOOPS_DRIFT   10000
+
+// test nudging the window by using a drifting HW clock
+TEST_F(ClockModelTestFixture, clock_no_drift) {
+    checkDriftingClock(SAMPLE_RATE, NUM_LOOPS_DRIFT);
+}
+
+// These slow drift rates caused errors when I disabled the code that handles
+// drifting in the clock model. So I think the test is valid.
+// It is unlikely that real hardware would be off by more than this amount.
+TEST_F(ClockModelTestFixture, clock_slow_drift) {
+    checkDriftingClock(0.998 * SAMPLE_RATE, NUM_LOOPS_DRIFT);
+}
+
+TEST_F(ClockModelTestFixture, clock_fast_drift) {
+    checkDriftingClock(1.002 * SAMPLE_RATE, NUM_LOOPS_DRIFT);
+}
\ No newline at end of file
diff --git a/media/libaaudio/tests/test_return_stop.cpp b/media/libaaudio/tests/test_return_stop.cpp
index 9a9e00c..1252dd3 100644
--- a/media/libaaudio/tests/test_return_stop.cpp
+++ b/media/libaaudio/tests/test_return_stop.cpp
@@ -140,7 +140,7 @@
     printf("%s() - error = %d\n", __func__, error);
 }
 
-void usage() {
+static void s_usage() {
     printf("test_return_stop [-i] [-x] [-n] [-c]\n");
     printf("     -i direction INPUT, otherwise OUTPUT\n");
     printf("     -x sharing mode EXCLUSIVE, otherwise SHARED\n");
@@ -148,6 +148,28 @@
     printf("     -c always return CONTINUE from callback, not STOP\n");
 }
 
+/**
+ * @return 0 is OK, -1 for error
+ */
+static int s_checkEnginePositions(AudioEngine *engine) {
+    const int64_t framesRead = AAudioStream_getFramesRead(engine->stream);
+    const int64_t framesWritten = AAudioStream_getFramesWritten(engine->stream);
+    const int32_t delta = (int32_t)(framesWritten - framesRead);
+    printf("playing framesRead = %7d, framesWritten = %7d"
+           ", delta = %4d, framesCalled = %6d, callbackCount = %4d\n",
+           (int32_t) framesRead,
+           (int32_t) framesWritten,
+           delta,
+           engine->framesCalled.load(),
+           engine->callbackCount.load()
+    );
+    if (delta > AAudioStream_getBufferCapacityInFrames(engine->stream)) {
+        printf("ERROR - delta > capacity\n");
+        return -1;
+    }
+    return 0;
+}
+
 int main(int argc, char **argv) {
     (void) argc;
     (void) argv;
@@ -188,12 +210,12 @@
                     sharingMode = AAUDIO_SHARING_MODE_EXCLUSIVE;
                     break;
                 default:
-                    usage();
+                    s_usage();
                     exit(EXIT_FAILURE);
                     break;
             }
         } else {
-            usage();
+            s_usage();
             exit(EXIT_FAILURE);
             break;
         }
@@ -201,12 +223,20 @@
 
     result = s_OpenAudioStream(&engine, direction, sharingMode, perfMode);
     if (result != AAUDIO_OK) {
-        printf("s_OpenAudioStream returned %s",
+        printf("s_OpenAudioStream returned %s\n",
                AAudio_convertResultToText(result));
         errorCount++;
     }
 
     int32_t framesPerBurst = AAudioStream_getFramesPerBurst(engine.stream);
+    // Use double buffered stream.
+    const int32_t bufferSize = AAudioStream_setBufferSizeInFrames(engine.stream, 2 * framesPerBurst);
+    if (bufferSize < 0) {
+        printf("AAudioStream_setBufferSizeInFrames returned %s\n",
+               AAudio_convertResultToText(bufferSize));
+        errorCount++;
+    }
+
     // Check to see what kind of stream we actually got.
     int32_t deviceId = AAudioStream_getDeviceId(engine.stream);
     aaudio_performance_mode_t actualPerfMode = AAudioStream_getPerformanceMode(engine.stream);
@@ -235,21 +265,14 @@
         if (result == AAUDIO_OK) {
             const int watchLoops = LOOP_DURATION_MSEC / SLEEP_DURATION_MSEC;
             for (int i = watchLoops; i > 0; i--) {
-                printf("playing silence #%02d, framesRead = %7d, framesWritten = %7d,"
-                       " framesCalled = %6d, callbackCount = %4d\n",
-                       i,
-                       (int32_t) AAudioStream_getFramesRead(engine.stream),
-                       (int32_t) AAudioStream_getFramesWritten(engine.stream),
-                       engine.framesCalled.load(),
-                       engine.callbackCount.load()
-                );
+                errorCount += s_checkEnginePositions(&engine) ? 1 : 0;
                 usleep(SLEEP_DURATION_MSEC * 1000);
             }
         }
 
         if (engine.stopAtFrame != INT32_MAX) {
             callbackResult = (engine.callbackCountAfterStop == 0) ? EXIT_SUCCESS
-                                                                             : EXIT_FAILURE;
+                                                                  : EXIT_FAILURE;
             if (callbackResult) {
                 printf("ERROR - Callback count after STOP = %d\n",
                        engine.callbackCountAfterStop.load());
@@ -268,9 +291,7 @@
             errorCount++;
         }
         usleep(SLEEP_DURATION_MSEC * 1000);
-        printf("getFramesRead() = %d, getFramesWritten() = %d\n",
-               (int32_t) AAudioStream_getFramesRead(engine.stream),
-               (int32_t) AAudioStream_getFramesWritten(engine.stream));
+        errorCount += s_checkEnginePositions(&engine) ? 1 : 0;
     }
 
     s_CloseAudioStream(&engine);
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 4c762ed..896198b 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -1281,6 +1281,20 @@
     return aps->getMasterMono(mono);
 }
 
+status_t AudioSystem::setMasterBalance(float balance)
+{
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return PERMISSION_DENIED;
+    return af->setMasterBalance(balance);
+}
+
+status_t AudioSystem::getMasterBalance(float *balance)
+{
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return PERMISSION_DENIED;
+    return af->getMasterBalance(balance);
+}
+
 float AudioSystem::getStreamVolumeDB(audio_stream_type_t stream, int index, audio_devices_t device)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index e9a0e22..c2ee2ee 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -293,6 +293,11 @@
       mPreviousSchedulingGroup(SP_DEFAULT),
       mPausedPosition(0)
 {
+    mAttributes.content_type = AUDIO_CONTENT_TYPE_UNKNOWN;
+    mAttributes.usage = AUDIO_USAGE_UNKNOWN;
+    mAttributes.flags = 0x0;
+    strcpy(mAttributes.tags, "");
+
     (void)set(streamType, sampleRate, format, channelMask,
             frameCount, flags, cbf, user, notificationFrames,
             0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType,
@@ -324,6 +329,11 @@
       mPausedPosition(0),
       mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE)
 {
+    mAttributes.content_type = AUDIO_CONTENT_TYPE_UNKNOWN;
+    mAttributes.usage = AUDIO_USAGE_UNKNOWN;
+    mAttributes.flags = 0x0;
+    strcpy(mAttributes.tags, "");
+
     (void)set(streamType, sampleRate, format, channelMask,
             0 /*frameCount*/, flags, cbf, user, notificationFrames,
             sharedBuffer, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo,
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 00678c2..825cd4e 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -87,6 +87,8 @@
     SYSTEM_READY,
     FRAME_COUNT_HAL,
     GET_MICROPHONES,
+    SET_MASTER_BALANCE,
+    GET_MASTER_BALANCE,
 };
 
 #define MAX_ITEMS_PER_LIST 1024
@@ -242,6 +244,34 @@
         return reply.readInt32();
     }
 
+    status_t setMasterBalance(float balance) override
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeFloat(balance);
+        status_t status = remote()->transact(SET_MASTER_BALANCE, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        return reply.readInt32();
+    }
+
+    status_t getMasterBalance(float *balance) const override
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        status_t status = remote()->transact(GET_MASTER_BALANCE, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        status = (status_t)reply.readInt32();
+        if (status != NO_ERROR) {
+            return status;
+        }
+        *balance = reply.readFloat();
+        return NO_ERROR;
+    }
+
     virtual status_t setStreamVolume(audio_stream_type_t stream, float value,
             audio_io_handle_t output)
     {
@@ -1050,6 +1080,21 @@
             reply->writeInt32( masterMute() );
             return NO_ERROR;
         } break;
+        case SET_MASTER_BALANCE: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            reply->writeInt32( setMasterBalance(data.readFloat()) );
+            return NO_ERROR;
+        } break;
+        case GET_MASTER_BALANCE: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            float f;
+            const status_t status = getMasterBalance(&f);
+            reply->writeInt32((int32_t)status);
+            if (status == NO_ERROR) {
+                (void)reply->writeFloat(f);
+            }
+            return NO_ERROR;
+        } break;
         case SET_STREAM_VOLUME: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             int stream = data.readInt32();
diff --git a/media/libaudioclient/include/media/AudioMixer.h b/media/libaudioclient/include/media/AudioMixer.h
index 3ae7104..fbbbd11 100644
--- a/media/libaudioclient/include/media/AudioMixer.h
+++ b/media/libaudioclient/include/media/AudioMixer.h
@@ -80,6 +80,7 @@
         MIXER_CHANNEL_MASK = 0x4006, // Channel mask for mixer output
         // for haptic
         HAPTIC_ENABLED  = 0x4007, // Set haptic data from this track should be played or not.
+        HAPTIC_INTENSITY = 0x4008, // Set the intensity to play haptic data.
         // for target RESAMPLE
         SAMPLE_RATE     = 0x4100, // Configure sample rate conversion on this track name;
                                   // parameter 'value' is the new sample rate in Hz.
@@ -102,6 +103,31 @@
                                   // parameter 'value' is a pointer to the new playback rate.
     };
 
+    enum { // Haptic intensity, should keep consistent with VibratorService
+        HAPTIC_SCALE_VERY_LOW = -2,
+        HAPTIC_SCALE_LOW = -1,
+        HAPTIC_SCALE_NONE = 0,
+        HAPTIC_SCALE_HIGH = 1,
+        HAPTIC_SCALE_VERY_HIGH = 2,
+    };
+    typedef int32_t haptic_intensity_t;
+    static constexpr float HAPTIC_SCALE_VERY_LOW_RATIO = 2 / 3;
+    static constexpr float HAPTIC_SCALE_LOW_RATIO = 3 / 4;
+    static const CONSTEXPR float HAPTIC_MAX_AMPLITUDE_FLOAT = 1.0f;
+
+    static inline bool isValidHapticIntensity(haptic_intensity_t hapticIntensity) {
+        switch (hapticIntensity) {
+        case HAPTIC_SCALE_VERY_LOW:
+        case HAPTIC_SCALE_LOW:
+        case HAPTIC_SCALE_NONE:
+        case HAPTIC_SCALE_HIGH:
+        case HAPTIC_SCALE_VERY_HIGH:
+            return true;
+        default:
+            return false;
+        }
+    }
+
     AudioMixer(size_t frameCount, uint32_t sampleRate)
         : mSampleRate(sampleRate)
         , mFrameCount(frameCount) {
@@ -147,6 +173,7 @@
             }
         }
         (this->*mHook)();
+        processHapticData();
     }
 
     size_t      getUnreleasedFrames(int name) const;
@@ -364,6 +391,7 @@
 
         // Haptic
         bool                 mHapticPlaybackEnabled;
+        haptic_intensity_t   mHapticIntensity;
         audio_channel_mask_t mHapticChannelMask;
         uint32_t             mHapticChannelCount;
         audio_channel_mask_t mMixerHapticChannelMask;
@@ -374,6 +402,37 @@
         uint32_t             mAdjustNonDestructiveOutChannelCount;
         bool                 mKeepContractedChannels;
 
+        float getHapticScaleGamma() const {
+        // Need to keep consistent with the value in VibratorService.
+        switch (mHapticIntensity) {
+        case HAPTIC_SCALE_VERY_LOW:
+            return 2.0f;
+        case HAPTIC_SCALE_LOW:
+            return 1.5f;
+        case HAPTIC_SCALE_HIGH:
+            return 0.5f;
+        case HAPTIC_SCALE_VERY_HIGH:
+            return 0.25f;
+        default:
+            return 1.0f;
+        }
+        }
+
+        float getHapticMaxAmplitudeRatio() const {
+        // Need to keep consistent with the value in VibratorService.
+        switch (mHapticIntensity) {
+        case HAPTIC_SCALE_VERY_LOW:
+            return HAPTIC_SCALE_VERY_LOW_RATIO;
+        case HAPTIC_SCALE_LOW:
+            return HAPTIC_SCALE_LOW_RATIO;
+        case HAPTIC_SCALE_NONE:
+        case HAPTIC_SCALE_HIGH:
+        case HAPTIC_SCALE_VERY_HIGH:
+        default:
+            return 1.0f;
+        }
+        }
+
     private:
         // hooks
         void track__genericResample(int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
@@ -410,6 +469,8 @@
     template <int MIXTYPE, typename TO, typename TI, typename TA>
     void process__noResampleOneTrack();
 
+    void processHapticData();
+
     static process_hook_t getProcessHook(int processType, uint32_t channelCount,
             audio_format_t mixerInFormat, audio_format_t mixerOutFormat);
 
diff --git a/media/libaudioclient/include/media/AudioRecord.h b/media/libaudioclient/include/media/AudioRecord.h
index ebee124..1f71844 100644
--- a/media/libaudioclient/include/media/AudioRecord.h
+++ b/media/libaudioclient/include/media/AudioRecord.h
@@ -719,7 +719,7 @@
 private:
     class MediaMetrics {
       public:
-        MediaMetrics() : mAnalyticsItem(new MediaAnalyticsItem("audiorecord")),
+        MediaMetrics() : mAnalyticsItem(MediaAnalyticsItem::create("audiorecord")),
                          mCreatedNs(systemTime(SYSTEM_TIME_REALTIME)),
                          mStartedNs(0), mDurationNs(0), mCount(0),
                          mLastError(NO_ERROR) {
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index a208602..1fb7add 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -339,6 +339,9 @@
     static status_t setMasterMono(bool mono);
     static status_t getMasterMono(bool *mono);
 
+    static status_t setMasterBalance(float balance);
+    static status_t getMasterBalance(float *balance);
+
     static float    getStreamVolumeDB(
             audio_stream_type_t stream, int index, audio_devices_t device);
 
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index 7fdf7cc..cbb750f 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -1227,7 +1227,7 @@
 private:
     class MediaMetrics {
       public:
-        MediaMetrics() : mAnalyticsItem(new MediaAnalyticsItem("audiotrack")) {
+        MediaMetrics() : mAnalyticsItem(MediaAnalyticsItem::create("audiotrack")) {
         }
         ~MediaMetrics() {
             // mAnalyticsItem alloc failure will be flagged in the constructor
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index a34b207..ef0ed0c 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -359,6 +359,9 @@
     virtual     float       masterVolume() const = 0;
     virtual     bool        masterMute() const = 0;
 
+    virtual     status_t    setMasterBalance(float balance) = 0;
+    virtual     status_t    getMasterBalance(float *balance) const = 0;
+
     /* set/get stream type state. This will probably be used by
      * the preference panel, mostly.
      */
diff --git a/media/libaudiohal/impl/StreamHalHidl.cpp b/media/libaudiohal/impl/StreamHalHidl.cpp
index 2e35be6..e396cf3 100644
--- a/media/libaudiohal/impl/StreamHalHidl.cpp
+++ b/media/libaudiohal/impl/StreamHalHidl.cpp
@@ -106,7 +106,7 @@
     status_t status = parametersFromHal(kvPairs, &hidlParams);
     if (status != OK) return status;
     return processReturn("setParameters",
-                         utils::setParameters(mStream, hidlParams, {} /* options */));
+                         utils::setParameters(mStream, {} /* context */, hidlParams));
 }
 
 status_t StreamHalHidl::getParameters(const String8& keys, String8 *values) {
diff --git a/media/libaudioprocessing/AudioMixer.cpp b/media/libaudioprocessing/AudioMixer.cpp
index 86711de..86777d6 100644
--- a/media/libaudioprocessing/AudioMixer.cpp
+++ b/media/libaudioprocessing/AudioMixer.cpp
@@ -167,6 +167,7 @@
         t->mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT;
         // haptic
         t->mHapticPlaybackEnabled = false;
+        t->mHapticIntensity = HAPTIC_SCALE_NONE;
         t->mMixerHapticChannelMask = AUDIO_CHANNEL_NONE;
         t->mMixerHapticChannelCount = 0;
         t->mAdjustInChannelCount = t->channelCount + t->mHapticChannelCount;
@@ -717,6 +718,12 @@
                 track->prepareForAdjustChannels();
             }
             } break;
+        case HAPTIC_INTENSITY: {
+            const haptic_intensity_t hapticIntensity = static_cast<haptic_intensity_t>(valueInt);
+            if (track->mHapticIntensity != hapticIntensity) {
+                track->mHapticIntensity = hapticIntensity;
+            }
+            } break;
         default:
             LOG_ALWAYS_FATAL("setParameter track: bad param %d", param);
         }
@@ -1846,6 +1853,40 @@
     }
 }
 
+void AudioMixer::processHapticData()
+{
+    // Need to keep consistent with VibrationEffect.scale(int, float, int)
+    for (const auto &pair : mGroups) {
+        // process by group of tracks with same output main buffer.
+        const auto &group = pair.second;
+        for (const int name : group) {
+            const std::shared_ptr<Track> &t = mTracks[name];
+            if (t->mHapticPlaybackEnabled) {
+                size_t sampleCount = mFrameCount * t->mMixerHapticChannelCount;
+                float gamma = t->getHapticScaleGamma();
+                float maxAmplitudeRatio = t->getHapticMaxAmplitudeRatio();
+                uint8_t* buffer = (uint8_t*)pair.first + mFrameCount * audio_bytes_per_frame(
+                        t->mMixerChannelCount, t->mMixerFormat);
+                switch (t->mMixerFormat) {
+                // Mixer format should be AUDIO_FORMAT_PCM_FLOAT.
+                case AUDIO_FORMAT_PCM_FLOAT: {
+                    float* fout = (float*) buffer;
+                    for (size_t i = 0; i < sampleCount; i++) {
+                        float mul = fout[i] >= 0 ? 1.0 : -1.0;
+                        fout[i] = powf(fabsf(fout[i] / HAPTIC_MAX_AMPLITUDE_FLOAT), gamma)
+                                * maxAmplitudeRatio * HAPTIC_MAX_AMPLITUDE_FLOAT * mul;
+                    }
+                } break;
+                default:
+                    LOG_ALWAYS_FATAL("bad mMixerFormat: %#x", t->mMixerFormat);
+                    break;
+                }
+                break;
+            }
+        }
+    }
+}
+
 /* This track hook is called to do resampling then mixing,
  * pulling from the track's upstream AudioBufferProvider.
  *
diff --git a/media/libmedia/CharacterEncodingDetector.cpp b/media/libmedia/CharacterEncodingDetector.cpp
index 990d260..5c6b981 100644
--- a/media/libmedia/CharacterEncodingDetector.cpp
+++ b/media/libmedia/CharacterEncodingDetector.cpp
@@ -28,6 +28,8 @@
 #include <unicode/ucsdet.h>
 #include <unicode/ustring.h>
 
+#include <cutils/properties.h>
+
 namespace android {
 
 CharacterEncodingDetector::CharacterEncodingDetector() {
@@ -38,6 +40,26 @@
         ALOGE("could not create UConverter for UTF-8");
         mUtf8Conv = NULL;
     }
+
+    // Read system locale setting from system property and map to ICU encoding names.
+    mLocaleEnc = NULL;
+    char locale_value[PROPERTY_VALUE_MAX] = "";
+    if (property_get("persist.sys.locale", locale_value, NULL) > 0) {
+        const size_t len = strnlen(locale_value, sizeof(locale_value));
+
+        if (len == 3 && !strncmp(locale_value, "und", 3)) {
+            // Undetermined
+        } else if (!strncmp(locale_value, "th", 2)) { // Thai
+            mLocaleEnc = "windows-874-2000";
+        }
+        if (mLocaleEnc != NULL) {
+            ALOGV("System locale encoding = %s", mLocaleEnc);
+        } else {
+            ALOGV("Didn't recognize system locale setting, defaulting to en_US");
+        }
+    } else {
+        ALOGV("Couldn't read system locale setting, assuming en_US");
+    }
 }
 
 CharacterEncodingDetector::~CharacterEncodingDetector() {
@@ -157,7 +179,11 @@
                 }
             }
 
-            if (bestCombinedMatch != NULL) {
+            if (mLocaleEnc != NULL && !goodmatch && highest < 50) {
+                combinedenc = mLocaleEnc;
+                ALOGV("confidence is low but we have recognized predefined encoding, "
+                        "so try this (%s) instead", mLocaleEnc);
+            } else if (bestCombinedMatch != NULL) {
                 combinedenc = ucsdet_getName(bestCombinedMatch, &status);
             } else {
                 combinedenc = "ISO-8859-1";
diff --git a/media/libmedia/include/media/CharacterEncodingDetector.h b/media/libmedia/include/media/CharacterEncodingDetector.h
index deaa377..62564b1 100644
--- a/media/libmedia/include/media/CharacterEncodingDetector.h
+++ b/media/libmedia/include/media/CharacterEncodingDetector.h
@@ -54,6 +54,7 @@
         StringArray     mValues;
 
         UConverter*     mUtf8Conv;
+        const char*     mLocaleEnc;
 };
 
 
diff --git a/media/libmedia/include/media/DrmHal.h b/media/libmedia/include/media/DrmHal.h
index 7be5cf2..a630bfd 100644
--- a/media/libmedia/include/media/DrmHal.h
+++ b/media/libmedia/include/media/DrmHal.h
@@ -63,9 +63,10 @@
 
     virtual status_t initCheck() const;
 
-    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16],
-                                         const String8& mimeType,
-                                         DrmPlugin::SecurityLevel level);
+    virtual status_t isCryptoSchemeSupported(const uint8_t uuid[16],
+                                             const String8& mimeType,
+                                             DrmPlugin::SecurityLevel level,
+                                             bool *isSupported);
 
     virtual status_t createPlugin(const uint8_t uuid[16],
                                   const String8 &appPackageName);
@@ -226,10 +227,11 @@
     status_t getPropertyStringInternal(String8 const &name, String8 &value) const;
     status_t getPropertyByteArrayInternal(String8 const &name,
                                           Vector<uint8_t> &value) const;
-    bool matchMimeTypeAndSecurityLevel(sp<IDrmFactory> &factory,
-                                       const uint8_t uuid[16],
-                                       const String8 &mimeType,
-                                       DrmPlugin::SecurityLevel level);
+    status_t matchMimeTypeAndSecurityLevel(const sp<IDrmFactory> &factory,
+                                           const uint8_t uuid[16],
+                                           const String8 &mimeType,
+                                           DrmPlugin::SecurityLevel level,
+                                           bool *isSupported);
 
     DISALLOW_EVIL_CONSTRUCTORS(DrmHal);
 };
diff --git a/media/libmedia/include/media/IDrm.h b/media/libmedia/include/media/IDrm.h
index a32756f..fbe80c6 100644
--- a/media/libmedia/include/media/IDrm.h
+++ b/media/libmedia/include/media/IDrm.h
@@ -34,9 +34,10 @@
 
     virtual status_t initCheck() const = 0;
 
-    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16],
-                                         const String8 &mimeType,
-                                         DrmPlugin::SecurityLevel securityLevel) = 0;
+    virtual status_t isCryptoSchemeSupported(const uint8_t uuid[16],
+                                             const String8 &mimeType,
+                                             DrmPlugin::SecurityLevel securityLevel,
+                                             bool *result) = 0;
 
     virtual status_t createPlugin(const uint8_t uuid[16],
                                   const String8 &appPackageName) = 0;
diff --git a/media/libmediametrics/include/MediaAnalyticsItem.h b/media/libmediametrics/include/MediaAnalyticsItem.h
index 2f9e7c2..4a36f6a 100644
--- a/media/libmediametrics/include/MediaAnalyticsItem.h
+++ b/media/libmediametrics/include/MediaAnalyticsItem.h
@@ -82,16 +82,19 @@
             PROTO_LAST = PROTO_V1,
         };
 
+    private:
+        // use the ::create() method instead
+        MediaAnalyticsItem();
+        MediaAnalyticsItem(Key);
+        MediaAnalyticsItem(const MediaAnalyticsItem&);
+        MediaAnalyticsItem &operator=(const MediaAnalyticsItem&);
 
     public:
 
-        // so clients do not need to know size details
         static MediaAnalyticsItem* create(Key key);
         static MediaAnalyticsItem* create();
 
         // access functions for the class
-        MediaAnalyticsItem();
-        MediaAnalyticsItem(Key);
         ~MediaAnalyticsItem();
 
         // SessionID ties multiple submissions for same key together
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 9bcfc83..96f79e0 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1906,10 +1906,16 @@
         if (AudioSystem::getOutputSamplingRate(&afSampleRate, mStreamType) != NO_ERROR) {
             return NO_INIT;
         }
+        if (afSampleRate == 0) {
+            return NO_INIT;
+        }
         const size_t framesPerBuffer =
                 (unsigned long long)sampleRate * afFrameCount / afSampleRate;
 
         if (bufferCount == 0) {
+            if (framesPerBuffer == 0) {
+                return NO_INIT;
+            }
             // use suggestedFrameCount
             bufferCount = (suggestedFrameCount + framesPerBuffer - 1) / framesPerBuffer;
         }
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index f2a3038..37b13f0 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -202,7 +202,7 @@
     }
     mAnalyticsDirty = false;
     if (reinitialize) {
-        mAnalyticsItem = new MediaAnalyticsItem(kKeyRecorder);
+        mAnalyticsItem = MediaAnalyticsItem::create(kKeyRecorder);
     }
 }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index a820445..1b396c0 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -97,7 +97,7 @@
     mMediaClock->init();
 
     // set up an analytics record
-    mAnalyticsItem = new MediaAnalyticsItem(kKeyPlayer);
+    mAnalyticsItem = MediaAnalyticsItem::create(kKeyPlayer);
 
     mLooper->start(
             false, /* runOnCallingThread */
@@ -635,7 +635,7 @@
 
         // re-init in case we prepare() and start() again.
         delete mAnalyticsItem ;
-        mAnalyticsItem = new MediaAnalyticsItem("nuplayer");
+        mAnalyticsItem = MediaAnalyticsItem::create("nuplayer");
         if (mAnalyticsItem) {
             mAnalyticsItem->setUid(mClientUid);
         }
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
index 67a0f1e..2d0c9e0 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
@@ -159,9 +159,12 @@
     if (drm != NULL) {
         for (size_t i = 0; i < psshDRMs.size(); i++) {
             DrmUUID uuid = psshDRMs[i];
-            if (drm->isCryptoSchemeSupported(uuid.ptr(), String8(),
-                            DrmPlugin::kSecurityLevelUnknown))
+            bool isSupported = false;
+            status = drm->isCryptoSchemeSupported(uuid.ptr(), String8(),
+                    DrmPlugin::kSecurityLevelUnknown, &isSupported);
+            if (status == OK && isSupported) {
                 supportedDRMs.add(uuid);
+            }
         }
 
         drm.clear();
diff --git a/media/libnblog/ReportPerformance.cpp b/media/libnblog/ReportPerformance.cpp
index f632e40..b050b83 100644
--- a/media/libnblog/ReportPerformance.cpp
+++ b/media/libnblog/ReportPerformance.cpp
@@ -168,7 +168,7 @@
         return false;
     }
 
-    std::unique_ptr<MediaAnalyticsItem> item(new MediaAnalyticsItem("audiothread"));
+    std::unique_ptr<MediaAnalyticsItem> item(MediaAnalyticsItem::create("audiothread"));
 
     const Histogram &workHist = data.workHist;
     if (workHist.totalCount() > 0) {
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 03eef48..26464b8 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -77,6 +77,41 @@
     },
 }
 
+cc_library_static {
+    name: "libstagefright_mpeg2extractor",
+
+    srcs: [
+        "Utils.cpp",
+        "MediaSource.cpp",
+        "HevcUtils.cpp",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libmedia",
+        "libmedia_omx",
+    ],
+
+    export_include_dirs: [
+        "include",
+    ],
+
+    cflags: [
+        "-Wno-multichar",
+        "-Werror",
+        "-Wno-error=deprecated-declarations",
+        "-Wall",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+    },
+}
+
 cc_library {
     name: "libstagefright",
 
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index c7da7c7..9c58e05 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -550,7 +550,7 @@
 
 void MediaCodec::initAnalyticsItem() {
     if (mAnalyticsItem == NULL) {
-        mAnalyticsItem = new MediaAnalyticsItem(kCodecKeyName);
+        mAnalyticsItem = MediaAnalyticsItem::create(kCodecKeyName);
     }
 
     mLatencyHist.setup(kLatencyHistBuckets, kLatencyHistWidth, kLatencyHistFloor);
diff --git a/media/libstagefright/MediaExtractorFactory.cpp b/media/libstagefright/MediaExtractorFactory.cpp
index 86402ce..19b174f 100644
--- a/media/libstagefright/MediaExtractorFactory.cpp
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -346,11 +346,13 @@
     ALOGV("search for plugins at %s", libDirPath);
     ALOGV("linked libs %s", gLinkedLibraries.c_str());
 
+    std::string libDirPathEx = libDirPath;
+    libDirPathEx += "/extractors";
     android_namespace_t *extractorNs = android_create_namespace("extractor",
             nullptr,  // ld_library_path
-            libDirPath,
+            libDirPath,  // default_library_path
             ANDROID_NAMESPACE_TYPE_ISOLATED,
-            nullptr,  // permitted_when_isolated_path
+            libDirPathEx.c_str(),  // permitted_when_isolated_path
             nullptr); // parent
     if (!android_link_namespaces(extractorNs, nullptr, gLinkedLibraries.c_str())) {
         ALOGE("Failed to link namespace. Failed to load extractor plug-ins in apex.");
@@ -361,7 +363,14 @@
         .library_namespace = extractorNs,
     };
 
-    DIR *libDir = opendir(libDirPath);
+    // try extractors subfolder first
+    DIR *libDir = opendir(libDirPathEx.c_str());
+
+    if (libDir) {
+        libDirPath = libDirPathEx.c_str();
+    } else {
+        libDir = opendir(libDirPath);
+    }
     if (libDir) {
         struct dirent* libEntry;
         while ((libEntry = readdir(libDir))) {
diff --git a/media/libstagefright/RemoteMediaExtractor.cpp b/media/libstagefright/RemoteMediaExtractor.cpp
index 9d2c42b..b0ce688 100644
--- a/media/libstagefright/RemoteMediaExtractor.cpp
+++ b/media/libstagefright/RemoteMediaExtractor.cpp
@@ -49,7 +49,7 @@
 
     mAnalyticsItem = nullptr;
     if (MEDIA_LOG) {
-        mAnalyticsItem = new MediaAnalyticsItem(kKeyExtractor);
+        mAnalyticsItem = MediaAnalyticsItem::create(kKeyExtractor);
 
         // track the container format (mpeg, aac, wvm, etc)
         size_t ntracks = extractor->countTracks();
diff --git a/media/libstagefright/codecs/g711/dec/SoftG711.cpp b/media/libstagefright/codecs/g711/dec/SoftG711.cpp
index c14983a..877cb5a 100644
--- a/media/libstagefright/codecs/g711/dec/SoftG711.cpp
+++ b/media/libstagefright/codecs/g711/dec/SoftG711.cpp
@@ -23,6 +23,8 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaDefs.h>
 
+#define MAX_CHANNEL_COUNT            6  /* maximum number of audio channels that can be decoded */
+
 namespace android {
 
 template<class T>
@@ -184,7 +186,7 @@
                 return OMX_ErrorUndefined;
             }
 
-            if (pcmParams->nChannels < 1 || pcmParams->nChannels > 2) {
+            if (pcmParams->nChannels < 1 || pcmParams->nChannels > MAX_CHANNEL_COUNT) {
                 return OMX_ErrorUndefined;
             }
 
diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
index 16179d3..4392799 100644
--- a/media/libstagefright/httplive/M3UParser.cpp
+++ b/media/libstagefright/httplive/M3UParser.cpp
@@ -706,6 +706,12 @@
         ++lineNo;
     }
 
+    // playlist has no item, would cause exception
+    if (mItems.size() == 0) {
+        ALOGE("playlist has no item");
+        return ERROR_MALFORMED;
+    }
+
     // error checking of all fields that's required to appear once
     // (currently only checking "target-duration"), and
     // initialization of playlist properties (eg. mTargetDurationUs)
diff --git a/media/libstagefright/rtsp/ASessionDescription.cpp b/media/libstagefright/rtsp/ASessionDescription.cpp
index 325084c..c581e9d 100644
--- a/media/libstagefright/rtsp/ASessionDescription.cpp
+++ b/media/libstagefright/rtsp/ASessionDescription.cpp
@@ -261,7 +261,7 @@
         return false;
     }
 
-    if (strncmp(value.c_str(), "npt=", 4)) {
+    if (strncmp(value.c_str(), "npt=", 4) && strncmp(value.c_str(), "npt:", 4)) {
         return false;
     }
 
diff --git a/media/mediaserver/Android.bp b/media/mediaserver/Android.bp
new file mode 100644
index 0000000..16c7be9
--- /dev/null
+++ b/media/mediaserver/Android.bp
@@ -0,0 +1,46 @@
+
+cc_library_static {
+    name: "libregistermsext",
+    srcs: ["register.cpp"],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+}
+
+cc_binary {
+    name: "mediaserver",
+
+    srcs: ["main_mediaserver.cpp"],
+
+    shared_libs: [
+        "libresourcemanagerservice",
+        "liblog",
+        "libmediaplayerservice",
+        "libutils",
+        "libbinder",
+        "libandroidicu",
+        "android.hardware.media.omx@1.0",
+    ],
+
+    static_libs: [
+        "libicuandroid_utils",
+        "libregistermsext",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libmediaplayerservice",
+        "frameworks/av/services/mediaresourcemanager",
+    ],
+
+    compile_multilib: "32",
+
+    init_rc: ["mediaserver.rc"],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+}
diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
deleted file mode 100644
index 1fbb85e..0000000
--- a/media/mediaserver/Android.mk
+++ /dev/null
@@ -1,41 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-ifneq ($(BOARD_USE_CUSTOM_MEDIASERVEREXTENSIONS),true)
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := register.cpp
-LOCAL_MODULE := libregistermsext
-LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS := -Werror -Wall
-include $(BUILD_STATIC_LIBRARY)
-endif
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-        main_mediaserver.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-        libresourcemanagerservice \
-        liblog \
-        libmediaplayerservice \
-        libutils \
-        libbinder \
-        libandroidicu \
-        android.hardware.media.omx@1.0 \
-
-LOCAL_STATIC_LIBRARIES := \
-        libicuandroid_utils \
-        libregistermsext
-
-LOCAL_C_INCLUDES := \
-        frameworks/av/media/libmediaplayerservice \
-        frameworks/av/services/mediaresourcemanager \
-
-LOCAL_MODULE:= mediaserver
-LOCAL_32_BIT_ONLY := true
-
-LOCAL_INIT_RC := mediaserver.rc
-
-LOCAL_CFLAGS := -Werror -Wall
-
-include $(BUILD_EXECUTABLE)
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index 9082f62..2deb1a4 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -274,7 +274,10 @@
     }
 
     String8 mimeStr = mimeType ? String8(mimeType) : String8("");
-    return drm->isCryptoSchemeSupported(uuid, mimeStr, DrmPlugin::kSecurityLevelUnknown);
+    bool isSupported = false;
+    status_t status = drm->isCryptoSchemeSupported(uuid, mimeStr,
+            DrmPlugin::kSecurityLevelUnknown, &isSupported);
+    return (status == OK) && isSupported;
 }
 
 EXPORT
diff --git a/packages/MediaComponents/apex/Android.bp b/packages/MediaComponents/apex/Android.bp
deleted file mode 100644
index d89eb77..0000000
--- a/packages/MediaComponents/apex/Android.bp
+++ /dev/null
@@ -1,41 +0,0 @@
-filegroup {
-    name: "media_aidl",
-    srcs: [
-        "java/android/media/**/*.aidl",
-        "java/android/service/**/*.aidl",
-    ],
-    exclude_srcs: [
-        // Exclude these aidls to avoid errors such as
-        // "Refusing to generate code with unstructured parcelables."
-        "java/android/media/MediaDescription.aidl",
-        "java/android/media/MediaMetadata.aidl",
-        // TODO(insun): check why MediaParceledListSlice.aidl should be added here
-        "java/android/media/MediaParceledListSlice.aidl",
-        "java/android/media/Rating.aidl",
-        "java/android/media/browse/MediaBrowser.aidl",
-        "java/android/media/session/MediaSession.aidl",
-        "java/android/media/session/ParcelableVolumeInfo.aidl",
-        "java/android/media/session/PlaybackState.aidl",
-    ],
-}
-
-java_library {
-    name: "media",
-    installable: true,
-    sdk_version: "system_current",
-    srcs: [
-        "java/android/media/**/*.java",
-        "java/android/service/**/*.java",
-        ":media_aidl",
-        ":framework-media-annotation-srcs",
-    ],
-    aidl: {
-        local_include_dirs: ["java"],
-        include_dirs: [
-            "frameworks/base/core/java",
-            // for android.graphics.Bitmap
-            // from IMediaBrowserServiceCallback
-            "frameworks/base/graphics/java",
-            ],
-    },
-}
diff --git a/packages/MediaComponents/apex/java/android/media/IRemoteVolumeController.aidl b/packages/MediaComponents/apex/java/android/media/IRemoteVolumeController.aidl
deleted file mode 100644
index e4a4a42..0000000
--- a/packages/MediaComponents/apex/java/android/media/IRemoteVolumeController.aidl
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2014 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 android.media.session.ISessionController;
-
-/**
- * AIDL for the MediaSessionService to report interesting events on remote playback
- * to a volume control dialog. See also IVolumeController for the AudioService half.
- * TODO add in better support for multiple remote sessions.
- * @hide
- */
-oneway interface IRemoteVolumeController {
-    void remoteVolumeChanged(ISessionController session, int flags);
-    // sets the default session to use with the slider, replaces remoteSliderVisibility
-    // on IVolumeController
-    void updateRemoteController(ISessionController session);
-}
diff --git a/packages/MediaComponents/apex/java/android/media/ISessionTokensListener.aidl b/packages/MediaComponents/apex/java/android/media/ISessionTokensListener.aidl
deleted file mode 100644
index c83a19e..0000000
--- a/packages/MediaComponents/apex/java/android/media/ISessionTokensListener.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * 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 android.os.Bundle;
-
-/**
- * Listens for changes to the list of session tokens.
- * @hide
- */
-oneway interface ISessionTokensListener {
-    void onSessionTokensChanged(in List<Bundle> tokens);
-}
diff --git a/packages/MediaComponents/apex/java/android/media/MediaDescription.aidl b/packages/MediaComponents/apex/java/android/media/MediaDescription.aidl
deleted file mode 100644
index 6f934f7..0000000
--- a/packages/MediaComponents/apex/java/android/media/MediaDescription.aidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/* Copyright 2014, 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;
-
-parcelable MediaDescription;
diff --git a/packages/MediaComponents/apex/java/android/media/MediaDescription.java b/packages/MediaComponents/apex/java/android/media/MediaDescription.java
deleted file mode 100644
index 31079e5..0000000
--- a/packages/MediaComponents/apex/java/android/media/MediaDescription.java
+++ /dev/null
@@ -1,383 +0,0 @@
-package android.media;
-
-import android.annotation.Nullable;
-import android.graphics.Bitmap;
-import android.media.browse.MediaBrowser;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-
-/**
- * A simple set of metadata for a media item suitable for display. This can be
- * created using the Builder or retrieved from existing metadata using
- * {@link MediaMetadata#getDescription()}.
- */
-public class MediaDescription implements Parcelable {
-    /**
-     * A unique persistent id for the content or null.
-     */
-    private final String mMediaId;
-    /**
-     * A primary title suitable for display or null.
-     */
-    private final CharSequence mTitle;
-    /**
-     * A subtitle suitable for display or null.
-     */
-    private final CharSequence mSubtitle;
-    /**
-     * A description suitable for display or null.
-     */
-    private final CharSequence mDescription;
-    /**
-     * A bitmap icon suitable for display or null.
-     */
-    private final Bitmap mIcon;
-    /**
-     * A Uri for an icon suitable for display or null.
-     */
-    private final Uri mIconUri;
-    /**
-     * Extras for opaque use by apps/system.
-     */
-    private final Bundle mExtras;
-    /**
-     * A Uri to identify this content.
-     */
-    private final Uri mMediaUri;
-
-    /**
-     * Used as a long extra field to indicate the bluetooth folder type of the media item as
-     * specified in the section 6.10.2.2 of the Bluetooth AVRCP 1.5. This is valid only for
-     * {@link MediaBrowser.MediaItem} with {@link MediaBrowser.MediaItem#FLAG_BROWSABLE}. The value
-     * should be one of the following:
-     * <ul>
-     * <li>{@link #BT_FOLDER_TYPE_MIXED}</li>
-     * <li>{@link #BT_FOLDER_TYPE_TITLES}</li>
-     * <li>{@link #BT_FOLDER_TYPE_ALBUMS}</li>
-     * <li>{@link #BT_FOLDER_TYPE_ARTISTS}</li>
-     * <li>{@link #BT_FOLDER_TYPE_GENRES}</li>
-     * <li>{@link #BT_FOLDER_TYPE_PLAYLISTS}</li>
-     * <li>{@link #BT_FOLDER_TYPE_YEARS}</li>
-     * </ul>
-     *
-     * @see #getExtras()
-     */
-    public static final String EXTRA_BT_FOLDER_TYPE = "android.media.extra.BT_FOLDER_TYPE";
-
-    /**
-     * The type of folder that is unknown or contains media elements of mixed types as specified in
-     * the section 6.10.2.2 of the Bluetooth AVRCP 1.5.
-     */
-    public static final long BT_FOLDER_TYPE_MIXED = 0;
-
-    /**
-     * The type of folder that contains media elements only as specified in the section 6.10.2.2 of
-     * the Bluetooth AVRCP 1.5.
-     */
-    public static final long BT_FOLDER_TYPE_TITLES = 1;
-
-    /**
-     * The type of folder that contains folders categorized by album as specified in the section
-     * 6.10.2.2 of the Bluetooth AVRCP 1.5.
-     */
-    public static final long BT_FOLDER_TYPE_ALBUMS = 2;
-
-    /**
-     * The type of folder that contains folders categorized by artist as specified in the section
-     * 6.10.2.2 of the Bluetooth AVRCP 1.5.
-     */
-    public static final long BT_FOLDER_TYPE_ARTISTS = 3;
-
-    /**
-     * The type of folder that contains folders categorized by genre as specified in the section
-     * 6.10.2.2 of the Bluetooth AVRCP 1.5.
-     */
-    public static final long BT_FOLDER_TYPE_GENRES = 4;
-
-    /**
-     * The type of folder that contains folders categorized by playlist as specified in the section
-     * 6.10.2.2 of the Bluetooth AVRCP 1.5.
-     */
-    public static final long BT_FOLDER_TYPE_PLAYLISTS = 5;
-
-    /**
-     * The type of folder that contains folders categorized by year as specified in the section
-     * 6.10.2.2 of the Bluetooth AVRCP 1.5.
-     */
-    public static final long BT_FOLDER_TYPE_YEARS = 6;
-
-    private MediaDescription(String mediaId, CharSequence title, CharSequence subtitle,
-            CharSequence description, Bitmap icon, Uri iconUri, Bundle extras, Uri mediaUri) {
-        mMediaId = mediaId;
-        mTitle = title;
-        mSubtitle = subtitle;
-        mDescription = description;
-        mIcon = icon;
-        mIconUri = iconUri;
-        mExtras = extras;
-        mMediaUri = mediaUri;
-    }
-
-    private MediaDescription(Parcel in) {
-        mMediaId = in.readString();
-        mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
-        mSubtitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
-        mDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
-        mIcon = in.readParcelable(null);
-        mIconUri = in.readParcelable(null);
-        mExtras = in.readBundle();
-        mMediaUri = in.readParcelable(null);
-    }
-
-    /**
-     * Returns the media id or null. See
-     * {@link MediaMetadata#METADATA_KEY_MEDIA_ID}.
-     */
-    public @Nullable String getMediaId() {
-        return mMediaId;
-    }
-
-    /**
-     * Returns a title suitable for display or null.
-     *
-     * @return A title or null.
-     */
-    public @Nullable CharSequence getTitle() {
-        return mTitle;
-    }
-
-    /**
-     * Returns a subtitle suitable for display or null.
-     *
-     * @return A subtitle or null.
-     */
-    public @Nullable CharSequence getSubtitle() {
-        return mSubtitle;
-    }
-
-    /**
-     * Returns a description suitable for display or null.
-     *
-     * @return A description or null.
-     */
-    public @Nullable CharSequence getDescription() {
-        return mDescription;
-    }
-
-    /**
-     * Returns a bitmap icon suitable for display or null.
-     *
-     * @return An icon or null.
-     */
-    public @Nullable Bitmap getIconBitmap() {
-        return mIcon;
-    }
-
-    /**
-     * Returns a Uri for an icon suitable for display or null.
-     *
-     * @return An icon uri or null.
-     */
-    public @Nullable Uri getIconUri() {
-        return mIconUri;
-    }
-
-    /**
-     * Returns any extras that were added to the description.
-     *
-     * @return A bundle of extras or null.
-     */
-    public @Nullable Bundle getExtras() {
-        return mExtras;
-    }
-
-    /**
-     * Returns a Uri representing this content or null.
-     *
-     * @return A media Uri or null.
-     */
-    public @Nullable Uri getMediaUri() {
-        return mMediaUri;
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeString(mMediaId);
-        TextUtils.writeToParcel(mTitle, dest, 0);
-        TextUtils.writeToParcel(mSubtitle, dest, 0);
-        TextUtils.writeToParcel(mDescription, dest, 0);
-        dest.writeParcelable(mIcon, flags);
-        dest.writeParcelable(mIconUri, flags);
-        dest.writeBundle(mExtras);
-        dest.writeParcelable(mMediaUri, flags);
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (o == null) {
-            return false;
-        }
-
-        if (!(o instanceof MediaDescription)){
-            return false;
-        }
-
-        final MediaDescription d = (MediaDescription) o;
-
-        if (!String.valueOf(mTitle).equals(String.valueOf(d.mTitle))) {
-            return false;
-        }
-
-        if (!String.valueOf(mSubtitle).equals(String.valueOf(d.mSubtitle))) {
-            return false;
-        }
-
-        if (!String.valueOf(mDescription).equals(String.valueOf(d.mDescription))) {
-            return false;
-        }
-
-        return true;
-    }
-
-    @Override
-    public String toString() {
-        return mTitle + ", " + mSubtitle + ", " + mDescription;
-    }
-
-    public static final Parcelable.Creator<MediaDescription> CREATOR =
-            new Parcelable.Creator<MediaDescription>() {
-                @Override
-                public MediaDescription createFromParcel(Parcel in) {
-                    return new MediaDescription(in);
-                }
-
-                @Override
-                public MediaDescription[] newArray(int size) {
-                    return new MediaDescription[size];
-                }
-            };
-
-    /**
-     * Builder for {@link MediaDescription} objects.
-     */
-    public static class Builder {
-        private String mMediaId;
-        private CharSequence mTitle;
-        private CharSequence mSubtitle;
-        private CharSequence mDescription;
-        private Bitmap mIcon;
-        private Uri mIconUri;
-        private Bundle mExtras;
-        private Uri mMediaUri;
-
-        /**
-         * Creates an initially empty builder.
-         */
-        public Builder() {
-        }
-
-        /**
-         * Sets the media id.
-         *
-         * @param mediaId The unique id for the item or null.
-         * @return this
-         */
-        public Builder setMediaId(@Nullable String mediaId) {
-            mMediaId = mediaId;
-            return this;
-        }
-
-        /**
-         * Sets the title.
-         *
-         * @param title A title suitable for display to the user or null.
-         * @return this
-         */
-        public Builder setTitle(@Nullable CharSequence title) {
-            mTitle = title;
-            return this;
-        }
-
-        /**
-         * Sets the subtitle.
-         *
-         * @param subtitle A subtitle suitable for display to the user or null.
-         * @return this
-         */
-        public Builder setSubtitle(@Nullable CharSequence subtitle) {
-            mSubtitle = subtitle;
-            return this;
-        }
-
-        /**
-         * Sets the description.
-         *
-         * @param description A description suitable for display to the user or
-         *            null.
-         * @return this
-         */
-        public Builder setDescription(@Nullable CharSequence description) {
-            mDescription = description;
-            return this;
-        }
-
-        /**
-         * Sets the icon.
-         *
-         * @param icon A {@link Bitmap} icon suitable for display to the user or
-         *            null.
-         * @return this
-         */
-        public Builder setIconBitmap(@Nullable Bitmap icon) {
-            mIcon = icon;
-            return this;
-        }
-
-        /**
-         * Sets the icon uri.
-         *
-         * @param iconUri A {@link Uri} for an icon suitable for display to the
-         *            user or null.
-         * @return this
-         */
-        public Builder setIconUri(@Nullable Uri iconUri) {
-            mIconUri = iconUri;
-            return this;
-        }
-
-        /**
-         * Sets a bundle of extras.
-         *
-         * @param extras The extras to include with this description or null.
-         * @return this
-         */
-        public Builder setExtras(@Nullable Bundle extras) {
-            mExtras = extras;
-            return this;
-        }
-
-        /**
-         * Sets the media uri.
-         *
-         * @param mediaUri The content's {@link Uri} for the item or null.
-         * @return this
-         */
-        public Builder setMediaUri(@Nullable Uri mediaUri) {
-            mMediaUri = mediaUri;
-            return this;
-        }
-
-        public MediaDescription build() {
-            return new MediaDescription(mMediaId, mTitle, mSubtitle, mDescription, mIcon, mIconUri,
-                    mExtras, mMediaUri);
-        }
-    }
-}
diff --git a/packages/MediaComponents/apex/java/android/media/MediaMetadata.aidl b/packages/MediaComponents/apex/java/android/media/MediaMetadata.aidl
deleted file mode 100644
index 66ee483..0000000
--- a/packages/MediaComponents/apex/java/android/media/MediaMetadata.aidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/* Copyright 2014, 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;
-
-parcelable MediaMetadata;
diff --git a/packages/MediaComponents/apex/java/android/media/MediaMetadata.java b/packages/MediaComponents/apex/java/android/media/MediaMetadata.java
deleted file mode 100644
index adfd20b..0000000
--- a/packages/MediaComponents/apex/java/android/media/MediaMetadata.java
+++ /dev/null
@@ -1,941 +0,0 @@
-/*
- * Copyright (C) 2014 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 android.annotation.NonNull;
-import android.annotation.StringDef;
-import android.annotation.UnsupportedAppUsage;
-import android.content.ContentResolver;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.media.browse.MediaBrowser;
-import android.media.session.MediaController;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.Log;
-import android.util.SparseArray;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Set;
-import java.util.Objects;
-
-/**
- * Contains metadata about an item, such as the title, artist, etc.
- */
-public final class MediaMetadata implements Parcelable {
-    private static final String TAG = "MediaMetadata";
-
-    /**
-     * @hide
-     */
-    @StringDef(prefix = { "METADATA_KEY_" }, value = {
-            METADATA_KEY_TITLE,
-            METADATA_KEY_ARTIST,
-            METADATA_KEY_ALBUM,
-            METADATA_KEY_AUTHOR,
-            METADATA_KEY_WRITER,
-            METADATA_KEY_COMPOSER,
-            METADATA_KEY_COMPILATION,
-            METADATA_KEY_DATE,
-            METADATA_KEY_GENRE,
-            METADATA_KEY_ALBUM_ARTIST,
-            METADATA_KEY_ART_URI,
-            METADATA_KEY_ALBUM_ART_URI,
-            METADATA_KEY_DISPLAY_TITLE,
-            METADATA_KEY_DISPLAY_SUBTITLE,
-            METADATA_KEY_DISPLAY_DESCRIPTION,
-            METADATA_KEY_DISPLAY_ICON_URI,
-            METADATA_KEY_MEDIA_ID,
-            METADATA_KEY_MEDIA_URI,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface TextKey {}
-
-    /**
-     * @hide
-     */
-    @StringDef(prefix = { "METADATA_KEY_" }, value = {
-            METADATA_KEY_DURATION,
-            METADATA_KEY_YEAR,
-            METADATA_KEY_TRACK_NUMBER,
-            METADATA_KEY_NUM_TRACKS,
-            METADATA_KEY_DISC_NUMBER,
-            METADATA_KEY_BT_FOLDER_TYPE,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface LongKey {}
-
-    /**
-     * @hide
-     */
-    @StringDef(prefix = { "METADATA_KEY_" }, value = {
-            METADATA_KEY_ART,
-            METADATA_KEY_ALBUM_ART,
-            METADATA_KEY_DISPLAY_ICON,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface BitmapKey {}
-
-    /**
-     * @hide
-     */
-    @StringDef(prefix = { "METADATA_KEY_" }, value = {
-            METADATA_KEY_USER_RATING,
-            METADATA_KEY_RATING,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface RatingKey {}
-
-    /**
-     * The title of the media.
-     */
-    public static final String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
-
-    /**
-     * The artist of the media.
-     */
-    public static final String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
-
-    /**
-     * The duration of the media in ms. A negative duration indicates that the
-     * duration is unknown (or infinite).
-     */
-    public static final String METADATA_KEY_DURATION = "android.media.metadata.DURATION";
-
-    /**
-     * The album title for the media.
-     */
-    public static final String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM";
-
-    /**
-     * The author of the media.
-     */
-    public static final String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR";
-
-    /**
-     * The writer of the media.
-     */
-    public static final String METADATA_KEY_WRITER = "android.media.metadata.WRITER";
-
-    /**
-     * The composer of the media.
-     */
-    public static final String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
-
-    /**
-     * The compilation status of the media.
-     */
-    public static final String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
-
-    /**
-     * The date the media was created or published. The format is unspecified
-     * but RFC 3339 is recommended.
-     */
-    public static final String METADATA_KEY_DATE = "android.media.metadata.DATE";
-
-    /**
-     * The year the media was created or published as a long.
-     */
-    public static final String METADATA_KEY_YEAR = "android.media.metadata.YEAR";
-
-    /**
-     * The genre of the media.
-     */
-    public static final String METADATA_KEY_GENRE = "android.media.metadata.GENRE";
-
-    /**
-     * The track number for the media.
-     */
-    public static final String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
-
-    /**
-     * The number of tracks in the media's original source.
-     */
-    public static final String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS";
-
-    /**
-     * The disc number for the media's original source.
-     */
-    public static final String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
-
-    /**
-     * The artist for the album of the media's original source.
-     */
-    public static final String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
-
-    /**
-     * The artwork for the media as a {@link Bitmap}.
-     * <p>
-     * The artwork should be relatively small and may be scaled down by the
-     * system if it is too large. For higher resolution artwork
-     * {@link #METADATA_KEY_ART_URI} should be used instead.
-     */
-    public static final String METADATA_KEY_ART = "android.media.metadata.ART";
-
-    /**
-     * The artwork for the media as a Uri formatted String. The artwork can be
-     * loaded using a combination of {@link ContentResolver#openInputStream} and
-     * {@link BitmapFactory#decodeStream}.
-     * <p>
-     * For the best results, Uris should use the content:// style and support
-     * {@link ContentResolver#EXTRA_SIZE} for retrieving scaled artwork through
-     * {@link ContentResolver#openTypedAssetFileDescriptor(Uri, String, Bundle)}.
-     */
-    public static final String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI";
-
-    /**
-     * The artwork for the album of the media's original source as a
-     * {@link Bitmap}.
-     * <p>
-     * The artwork should be relatively small and may be scaled down by the
-     * system if it is too large. For higher resolution artwork
-     * {@link #METADATA_KEY_ALBUM_ART_URI} should be used instead.
-     */
-    public static final String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART";
-
-    /**
-     * The artwork for the album of the media's original source as a Uri
-     * formatted String. The artwork can be loaded using a combination of
-     * {@link ContentResolver#openInputStream} and
-     * {@link BitmapFactory#decodeStream}.
-     * <p>
-     * For the best results, Uris should use the content:// style and support
-     * {@link ContentResolver#EXTRA_SIZE} for retrieving scaled artwork through
-     * {@link ContentResolver#openTypedAssetFileDescriptor(Uri, String, Bundle)}.
-     */
-    public static final String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI";
-
-    /**
-     * The user's rating for the media.
-     *
-     * @see Rating
-     */
-    public static final String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING";
-
-    /**
-     * The overall rating for the media.
-     *
-     * @see Rating
-     */
-    public static final String METADATA_KEY_RATING = "android.media.metadata.RATING";
-
-    /**
-     * A title that is suitable for display to the user. This will generally be
-     * the same as {@link #METADATA_KEY_TITLE} but may differ for some formats.
-     * When displaying media described by this metadata this should be preferred
-     * if present.
-     */
-    public static final String METADATA_KEY_DISPLAY_TITLE = "android.media.metadata.DISPLAY_TITLE";
-
-    /**
-     * A subtitle that is suitable for display to the user. When displaying a
-     * second line for media described by this metadata this should be preferred
-     * to other fields if present.
-     */
-    public static final String METADATA_KEY_DISPLAY_SUBTITLE
-            = "android.media.metadata.DISPLAY_SUBTITLE";
-
-    /**
-     * A description that is suitable for display to the user. When displaying
-     * more information for media described by this metadata this should be
-     * preferred to other fields if present.
-     */
-    public static final String METADATA_KEY_DISPLAY_DESCRIPTION
-            = "android.media.metadata.DISPLAY_DESCRIPTION";
-
-    /**
-     * An icon or thumbnail that is suitable for display to the user. When
-     * displaying an icon for media described by this metadata this should be
-     * preferred to other fields if present. This must be a {@link Bitmap}.
-     * <p>
-     * The icon should be relatively small and may be scaled down by the system
-     * if it is too large. For higher resolution artwork
-     * {@link #METADATA_KEY_DISPLAY_ICON_URI} should be used instead.
-     */
-    public static final String METADATA_KEY_DISPLAY_ICON
-            = "android.media.metadata.DISPLAY_ICON";
-
-    /**
-     * A Uri formatted String for an icon or thumbnail that is suitable for
-     * display to the user. When displaying more information for media described
-     * by this metadata the display description should be preferred to other
-     * fields when present. The icon can be loaded using a combination of
-     * {@link ContentResolver#openInputStream} and
-     * {@link BitmapFactory#decodeStream}.
-     * <p>
-     * For the best results, Uris should use the content:// style and support
-     * {@link ContentResolver#EXTRA_SIZE} for retrieving scaled artwork through
-     * {@link ContentResolver#openTypedAssetFileDescriptor(Uri, String, Bundle)}.
-     */
-    public static final String METADATA_KEY_DISPLAY_ICON_URI
-            = "android.media.metadata.DISPLAY_ICON_URI";
-
-    /**
-     * A String key for identifying the content. This value is specific to the
-     * service providing the content. If used, this should be a persistent
-     * unique key for the underlying content. It may be used with
-     * {@link MediaController.TransportControls#playFromMediaId(String, Bundle)}
-     * to initiate playback when provided by a {@link MediaBrowser} connected to
-     * the same app.
-     */
-    public static final String METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID";
-
-    /**
-     * A Uri formatted String representing the content. This value is specific to the
-     * service providing the content. It may be used with
-     * {@link MediaController.TransportControls#playFromUri(Uri, Bundle)}
-     * to initiate playback when provided by a {@link MediaBrowser} connected to
-     * the same app.
-     */
-    public static final String METADATA_KEY_MEDIA_URI = "android.media.metadata.MEDIA_URI";
-
-    /**
-     * The bluetooth folder type of the media specified in the section 6.10.2.2 of the Bluetooth
-     * AVRCP 1.5. It should be one of the following:
-     * <ul>
-     * <li>{@link MediaDescription#BT_FOLDER_TYPE_MIXED}</li>
-     * <li>{@link MediaDescription#BT_FOLDER_TYPE_TITLES}</li>
-     * <li>{@link MediaDescription#BT_FOLDER_TYPE_ALBUMS}</li>
-     * <li>{@link MediaDescription#BT_FOLDER_TYPE_ARTISTS}</li>
-     * <li>{@link MediaDescription#BT_FOLDER_TYPE_GENRES}</li>
-     * <li>{@link MediaDescription#BT_FOLDER_TYPE_PLAYLISTS}</li>
-     * <li>{@link MediaDescription#BT_FOLDER_TYPE_YEARS}</li>
-     * </ul>
-     */
-    public static final String METADATA_KEY_BT_FOLDER_TYPE
-            = "android.media.metadata.BT_FOLDER_TYPE";
-
-    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 static final int METADATA_TYPE_INVALID = -1;
-    private static final int METADATA_TYPE_LONG = 0;
-    private static final int METADATA_TYPE_TEXT = 1;
-    private static final int METADATA_TYPE_BITMAP = 2;
-    private static final int METADATA_TYPE_RATING = 3;
-    private 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_BT_FOLDER_TYPE, METADATA_TYPE_LONG);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_MEDIA_ID, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_MEDIA_URI, METADATA_TYPE_TEXT);
-    }
-
-    private static final SparseArray<String> EDITOR_KEY_MAPPING;
-
-    static {
-        EDITOR_KEY_MAPPING = new SparseArray<String>();
-        EDITOR_KEY_MAPPING.put(MediaMetadataEditor.BITMAP_KEY_ARTWORK, METADATA_KEY_ART);
-        EDITOR_KEY_MAPPING.put(MediaMetadataEditor.RATING_KEY_BY_OTHERS, METADATA_KEY_RATING);
-        EDITOR_KEY_MAPPING.put(MediaMetadataEditor.RATING_KEY_BY_USER, METADATA_KEY_USER_RATING);
-        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_ALBUM, METADATA_KEY_ALBUM);
-        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST,
-                METADATA_KEY_ALBUM_ARTIST);
-        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_ARTIST, METADATA_KEY_ARTIST);
-        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_AUTHOR, METADATA_KEY_AUTHOR);
-        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER,
-                METADATA_KEY_TRACK_NUMBER);
-        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_COMPOSER, METADATA_KEY_COMPOSER);
-        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_COMPILATION,
-                METADATA_KEY_COMPILATION);
-        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_DATE, METADATA_KEY_DATE);
-        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER,
-                METADATA_KEY_DISC_NUMBER);
-        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_DURATION, METADATA_KEY_DURATION);
-        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_GENRE, METADATA_KEY_GENRE);
-        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS,
-                METADATA_KEY_NUM_TRACKS);
-        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_TITLE, METADATA_KEY_TITLE);
-        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_WRITER, METADATA_KEY_WRITER);
-        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_YEAR, METADATA_KEY_YEAR);
-    }
-
-    private final Bundle mBundle;
-    private MediaDescription mDescription;
-
-    private MediaMetadata(Bundle bundle) {
-        mBundle = new Bundle(bundle);
-    }
-
-    private MediaMetadata(Parcel in) {
-        mBundle = in.readBundle();
-    }
-
-    /**
-     * Returns true if the given key is contained in the metadata
-     *
-     * @param key a String key
-     * @return true if the key exists in this metadata, false otherwise
-     */
-    public boolean containsKey(String key) {
-        return mBundle.containsKey(key);
-    }
-
-    /**
-     * Returns the value associated with the given key, or null if no mapping of
-     * the desired type exists for the given key or a null value is explicitly
-     * associated with the key.
-     *
-     * @param key The key the value is stored under
-     * @return a CharSequence value, or null
-     */
-    public CharSequence getText(@TextKey String key) {
-        return mBundle.getCharSequence(key);
-    }
-
-    /**
-     * Returns the text value associated with the given key as a String, or null
-     * if no mapping of the desired type exists for the given key or a null
-     * value is explicitly associated with the key. This is equivalent to
-     * calling {@link #getText getText().toString()} if the value is not null.
-     *
-     * @param key The key the value is stored under
-     * @return a String value, or null
-     */
-    public String getString(@TextKey String key) {
-        CharSequence text = getText(key);
-        if (text != null) {
-            return text.toString();
-        }
-        return null;
-    }
-
-    /**
-     * Returns the value associated with the given key, or 0L if no long exists
-     * for the given key.
-     *
-     * @param key The key the value is stored under
-     * @return a long value
-     */
-    public long getLong(@LongKey String key) {
-        return mBundle.getLong(key, 0);
-    }
-
-    /**
-     * Returns a {@link Rating} for the given key or null if no rating exists
-     * for the given key.
-     *
-     * @param key The key the value is stored under
-     * @return A {@link Rating} or null
-     */
-    public Rating getRating(@RatingKey String key) {
-        Rating rating = null;
-        try {
-            rating = mBundle.getParcelable(key);
-        } catch (Exception e) {
-            // ignore, value was not a bitmap
-            Log.w(TAG, "Failed to retrieve a key as Rating.", e);
-        }
-        return rating;
-    }
-
-    /**
-     * Returns a {@link Bitmap} for the given key or null if no bitmap exists
-     * for the given key.
-     *
-     * @param key The key the value is stored under
-     * @return A {@link Bitmap} or null
-     */
-    public Bitmap getBitmap(@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 int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeBundle(mBundle);
-    }
-
-    /**
-     * Returns the number of fields in this metadata.
-     *
-     * @return The number of fields in the metadata.
-     */
-    public int size() {
-        return mBundle.size();
-    }
-
-    /**
-     * Returns a Set containing the Strings used as keys in this metadata.
-     *
-     * @return a Set of String keys
-     */
-    public Set<String> keySet() {
-        return mBundle.keySet();
-    }
-
-    /**
-     * Returns a simple description of this metadata for display purposes.
-     *
-     * @return A simple description of this metadata.
-     */
-    public @NonNull MediaDescription getDescription() {
-        if (mDescription != null) {
-            return mDescription;
-        }
-
-        String mediaId = getString(METADATA_KEY_MEDIA_ID);
-
-        CharSequence[] text = new CharSequence[3];
-        Bitmap icon = null;
-        Uri iconUri = null;
-
-        // First handle the case where display data is set already
-        CharSequence displayText = getText(METADATA_KEY_DISPLAY_TITLE);
-        if (!TextUtils.isEmpty(displayText)) {
-            // If they have a display title use only display data, otherwise use
-            // our best bets
-            text[0] = displayText;
-            text[1] = getText(METADATA_KEY_DISPLAY_SUBTITLE);
-            text[2] = getText(METADATA_KEY_DISPLAY_DESCRIPTION);
-        } else {
-            // Use whatever fields we can
-            int textIndex = 0;
-            int keyIndex = 0;
-            while (textIndex < text.length && keyIndex < PREFERRED_DESCRIPTION_ORDER.length) {
-                CharSequence next = getText(PREFERRED_DESCRIPTION_ORDER[keyIndex++]);
-                if (!TextUtils.isEmpty(next)) {
-                    // Fill in the next empty bit of text
-                    text[textIndex++] = next;
-                }
-            }
-        }
-
-        // Get the best art bitmap we can find
-        for (int i = 0; i < PREFERRED_BITMAP_ORDER.length; i++) {
-            Bitmap next = getBitmap(PREFERRED_BITMAP_ORDER[i]);
-            if (next != null) {
-                icon = next;
-                break;
-            }
-        }
-
-        // Get the best Uri we can find
-        for (int i = 0; i < PREFERRED_URI_ORDER.length; i++) {
-            String next = getString(PREFERRED_URI_ORDER[i]);
-            if (!TextUtils.isEmpty(next)) {
-                iconUri = Uri.parse(next);
-                break;
-            }
-        }
-
-        Uri mediaUri = null;
-        String mediaUriStr = getString(METADATA_KEY_MEDIA_URI);
-        if (!TextUtils.isEmpty(mediaUriStr)) {
-            mediaUri = Uri.parse(mediaUriStr);
-        }
-
-        MediaDescription.Builder bob = new MediaDescription.Builder();
-        bob.setMediaId(mediaId);
-        bob.setTitle(text[0]);
-        bob.setSubtitle(text[1]);
-        bob.setDescription(text[2]);
-        bob.setIconBitmap(icon);
-        bob.setIconUri(iconUri);
-        bob.setMediaUri(mediaUri);
-        if (mBundle.containsKey(METADATA_KEY_BT_FOLDER_TYPE)) {
-            Bundle bundle = new Bundle();
-            bundle.putLong(MediaDescription.EXTRA_BT_FOLDER_TYPE,
-                    getLong(METADATA_KEY_BT_FOLDER_TYPE));
-            bob.setExtras(bundle);
-        }
-        mDescription = bob.build();
-
-        return mDescription;
-    }
-
-    /**
-     * Helper for getting the String key used by {@link MediaMetadata} from the
-     * integer key that {@link MediaMetadataEditor} uses.
-     *
-     * @param editorKey The key used by the editor
-     * @return The key used by this class or null if no mapping exists
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public static String getKeyFromMetadataEditorKey(int editorKey) {
-        return EDITOR_KEY_MAPPING.get(editorKey, null);
-    }
-
-    public static final Parcelable.Creator<MediaMetadata> CREATOR =
-            new Parcelable.Creator<MediaMetadata>() {
-                @Override
-                public MediaMetadata createFromParcel(Parcel in) {
-                    return new MediaMetadata(in);
-                }
-
-                @Override
-                public MediaMetadata[] newArray(int size) {
-                    return new MediaMetadata[size];
-                }
-            };
-
-    /**
-     * Compares the contents of this object to another MediaMetadata object. It
-     * does not compare Bitmaps and Ratings as the media player can choose to
-     * forgo these fields depending on how you retrieve the MediaMetadata.
-     *
-     * @param o The Metadata object to compare this object against
-     * @return Whether or not the two objects have matching fields (excluding
-     * Bitmaps and Ratings)
-     */
-    @Override
-    public boolean equals(Object o) {
-        if (o == this) {
-            return true;
-        }
-
-        if (!(o instanceof MediaMetadata)) {
-            return false;
-        }
-
-        final MediaMetadata m = (MediaMetadata) o;
-
-        for (int i = 0; i < METADATA_KEYS_TYPE.size(); i++) {
-            String key = METADATA_KEYS_TYPE.keyAt(i);
-            switch (METADATA_KEYS_TYPE.valueAt(i)) {
-                case METADATA_TYPE_TEXT:
-                    if (!Objects.equals(getString(key), m.getString(key))) {
-                        return false;
-                    }
-                    break;
-                case METADATA_TYPE_LONG:
-                    if (getLong(key) != m.getLong(key)) {
-                        return false;
-                    }
-                    break;
-                default:
-                    // Ignore ratings and bitmaps when comparing
-                    break;
-            }
-        }
-
-        return true;
-    }
-
-    @Override
-    public int hashCode() {
-        int hashCode = 17;
-
-        for (int i = 0; i < METADATA_KEYS_TYPE.size(); i++) {
-            String key = METADATA_KEYS_TYPE.keyAt(i);
-            switch (METADATA_KEYS_TYPE.valueAt(i)) {
-                case METADATA_TYPE_TEXT:
-                    hashCode = 31 * hashCode + Objects.hash(getString(key));
-                    break;
-                case METADATA_TYPE_LONG:
-                    hashCode = 31 * hashCode + Long.hashCode(getLong(key));
-                    break;
-                default:
-                    // Ignore ratings and bitmaps when comparing
-                    break;
-            }
-        }
-
-        return hashCode;
-    }
-
-    /**
-     * Use to build MediaMetadata objects. The system defined metadata keys must
-     * use the appropriate data type.
-     */
-    public static final class Builder {
-        private final Bundle mBundle;
-
-        /**
-         * Create an empty Builder. Any field that should be included in the
-         * {@link MediaMetadata} must be added.
-         */
-        public Builder() {
-            mBundle = new Bundle();
-        }
-
-        /**
-         * Create a Builder using a {@link MediaMetadata} instance to set the
-         * initial values. All fields in the source metadata will be included in
-         * the new metadata. Fields can be overwritten by adding the same key.
-         *
-         * @param source
-         */
-        public Builder(MediaMetadata source) {
-            mBundle = new Bundle(source.mBundle);
-        }
-
-        /**
-         * Create a Builder using a {@link MediaMetadata} instance to set
-         * initial values, but replace bitmaps with a scaled down copy if they
-         * are larger than maxBitmapSize.
-         *
-         * @param source The original metadata to copy.
-         * @param maxBitmapSize The maximum height/width for bitmaps contained
-         *            in the metadata.
-         * @hide
-         */
-        public Builder(MediaMetadata source, int maxBitmapSize) {
-            this(source);
-            for (String key : mBundle.keySet()) {
-                Object value = mBundle.get(key);
-                if (value != null && value instanceof Bitmap) {
-                    Bitmap bmp = (Bitmap) value;
-                    if (bmp.getHeight() > maxBitmapSize || bmp.getWidth() > maxBitmapSize) {
-                        putBitmap(key, scaleBitmap(bmp, maxBitmapSize));
-                    }
-                }
-            }
-        }
-
-        /**
-         * Put a CharSequence value into the metadata. Custom keys may be used,
-         * but if the METADATA_KEYs defined in this class are used they may only
-         * be one of the following:
-         * <ul>
-         * <li>{@link #METADATA_KEY_TITLE}</li>
-         * <li>{@link #METADATA_KEY_ARTIST}</li>
-         * <li>{@link #METADATA_KEY_ALBUM}</li>
-         * <li>{@link #METADATA_KEY_AUTHOR}</li>
-         * <li>{@link #METADATA_KEY_WRITER}</li>
-         * <li>{@link #METADATA_KEY_COMPOSER}</li>
-         * <li>{@link #METADATA_KEY_DATE}</li>
-         * <li>{@link #METADATA_KEY_GENRE}</li>
-         * <li>{@link #METADATA_KEY_ALBUM_ARTIST}</li>
-         * <li>{@link #METADATA_KEY_ART_URI}</li>
-         * <li>{@link #METADATA_KEY_ALBUM_ART_URI}</li>
-         * <li>{@link #METADATA_KEY_DISPLAY_TITLE}</li>
-         * <li>{@link #METADATA_KEY_DISPLAY_SUBTITLE}</li>
-         * <li>{@link #METADATA_KEY_DISPLAY_DESCRIPTION}</li>
-         * <li>{@link #METADATA_KEY_DISPLAY_ICON_URI}</li>
-         * </ul>
-         *
-         * @param key The key for referencing this value
-         * @param value The CharSequence value to store
-         * @return The Builder to allow chaining
-         */
-        public Builder putText(@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 this;
-        }
-
-        /**
-         * Put a String value into the metadata. Custom keys may be used, but if
-         * the METADATA_KEYs defined in this class are used they may only be one
-         * of the following:
-         * <ul>
-         * <li>{@link #METADATA_KEY_TITLE}</li>
-         * <li>{@link #METADATA_KEY_ARTIST}</li>
-         * <li>{@link #METADATA_KEY_ALBUM}</li>
-         * <li>{@link #METADATA_KEY_AUTHOR}</li>
-         * <li>{@link #METADATA_KEY_WRITER}</li>
-         * <li>{@link #METADATA_KEY_COMPOSER}</li>
-         * <li>{@link #METADATA_KEY_DATE}</li>
-         * <li>{@link #METADATA_KEY_GENRE}</li>
-         * <li>{@link #METADATA_KEY_ALBUM_ARTIST}</li>
-         * <li>{@link #METADATA_KEY_ART_URI}</li>
-         * <li>{@link #METADATA_KEY_ALBUM_ART_URI}</li>
-         * <li>{@link #METADATA_KEY_DISPLAY_TITLE}</li>
-         * <li>{@link #METADATA_KEY_DISPLAY_SUBTITLE}</li>
-         * <li>{@link #METADATA_KEY_DISPLAY_DESCRIPTION}</li>
-         * <li>{@link #METADATA_KEY_DISPLAY_ICON_URI}</li>
-         * </ul>
-         * <p>
-         * Uris for artwork should use the content:// style and support
-         * {@link ContentResolver#EXTRA_SIZE} for retrieving scaled artwork
-         * through {@link ContentResolver#openTypedAssetFileDescriptor(Uri,
-         * String, Bundle)}.
-         *
-         * @param key The key for referencing this value
-         * @param value The String value to store
-         * @return The Builder to allow chaining
-         */
-        public Builder putString(@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 this;
-        }
-
-        /**
-         * Put a long value into the metadata. Custom keys may be used, but if
-         * the METADATA_KEYs defined in this class are used they may only be one
-         * of the following:
-         * <ul>
-         * <li>{@link #METADATA_KEY_DURATION}</li>
-         * <li>{@link #METADATA_KEY_TRACK_NUMBER}</li>
-         * <li>{@link #METADATA_KEY_NUM_TRACKS}</li>
-         * <li>{@link #METADATA_KEY_DISC_NUMBER}</li>
-         * <li>{@link #METADATA_KEY_YEAR}</li>
-         * </ul>
-         *
-         * @param key The key for referencing this value
-         * @param value The long value to store
-         * @return The Builder to allow chaining
-         */
-        public Builder putLong(@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 this;
-        }
-
-        /**
-         * Put a {@link Rating} into the metadata. Custom keys may be used, but
-         * if the METADATA_KEYs defined in this class are used they may only be
-         * one of the following:
-         * <ul>
-         * <li>{@link #METADATA_KEY_RATING}</li>
-         * <li>{@link #METADATA_KEY_USER_RATING}</li>
-         * </ul>
-         *
-         * @param key The key for referencing this value
-         * @param value The Rating value to store
-         * @return The Builder to allow chaining
-         */
-        public Builder putRating(@RatingKey String key, Rating 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.putParcelable(key, value);
-            return this;
-        }
-
-        /**
-         * Put a {@link Bitmap} into the metadata. Custom keys may be used, but
-         * if the METADATA_KEYs defined in this class are used they may only be
-         * one of the following:
-         * <ul>
-         * <li>{@link #METADATA_KEY_ART}</li>
-         * <li>{@link #METADATA_KEY_ALBUM_ART}</li>
-         * <li>{@link #METADATA_KEY_DISPLAY_ICON}</li>
-         * </ul>
-         * <p>
-         * Large bitmaps may be scaled down by the system when
-         * {@link android.media.session.MediaSession#setMetadata} is called.
-         * To pass full resolution images {@link Uri Uris} should be used with
-         * {@link #putString}.
-         *
-         * @param key The key for referencing this value
-         * @param value The Bitmap to store
-         * @return The Builder to allow chaining
-         */
-        public Builder putBitmap(@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 this;
-        }
-
-        /**
-         * Creates a {@link MediaMetadata} instance with the specified fields.
-         *
-         * @return The new MediaMetadata instance
-         */
-        public MediaMetadata build() {
-            return new MediaMetadata(mBundle);
-        }
-
-        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/apex/java/android/media/MediaParceledListSlice.aidl b/packages/MediaComponents/apex/java/android/media/MediaParceledListSlice.aidl
deleted file mode 100644
index 228ea9c..0000000
--- a/packages/MediaComponents/apex/java/android/media/MediaParceledListSlice.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/* 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.
- */
-
-package android.media;
-
-/** @hide */
-parcelable MediaParceledListSlice;
\ No newline at end of file
diff --git a/packages/MediaComponents/apex/java/android/media/MediaParceledListSlice.java b/packages/MediaComponents/apex/java/android/media/MediaParceledListSlice.java
deleted file mode 100644
index ec3fdb7..0000000
--- a/packages/MediaComponents/apex/java/android/media/MediaParceledListSlice.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * 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 android.annotation.UnsupportedAppUsage;
-import android.os.Binder;
-import android.os.Build;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Transfer a large list of objects across an IPC. Splits into multiple transactions if needed.
- * Note: Only use classes declared final in order to avoid subclasses overriding reading/writing
- * parcel logic.
- *
- * TODO: Add test for sending large data
- * @hide
- */
-public class MediaParceledListSlice<T extends Parcelable> implements Parcelable {
-    private static final String TAG = "MediaParceledListSlice";
-    private static final boolean DEBUG = false;
-
-    private static final int MAX_IPC_SIZE = 64 * 1024; // IBinder.MAX_IPC_SIZE
-
-    final List<T> mList;
-
-    public MediaParceledListSlice(List<T> list) {
-        if (list == null) {
-            throw new IllegalArgumentException("list shouldn't be null");
-        }
-        mList = list;
-    }
-
-    MediaParceledListSlice(Parcel p) {
-        final int itemCount = p.readInt();
-        mList = new ArrayList<>(itemCount);
-        if (DEBUG) {
-            Log.d(TAG, "Retrieving " + itemCount + " items");
-        }
-        if (itemCount <= 0) {
-            return;
-        }
-
-        int i = 0;
-        while (i < itemCount) {
-            if (p.readInt() == 0) {
-                break;
-            }
-
-            final T parcelable = p.readParcelable(null);
-            mList.add(parcelable);
-
-            if (DEBUG) {
-                Log.d(TAG, "Read inline #" + i + ": " + mList.get(mList.size() - 1));
-            }
-            i++;
-        }
-        if (i >= itemCount) {
-            return;
-        }
-        final IBinder retriever = p.readStrongBinder();
-        while (i < itemCount) {
-            if (DEBUG) {
-                Log.d(TAG, "Reading more @" + i + " of " + itemCount + ": retriever=" + retriever);
-            }
-            Parcel data = Parcel.obtain();
-            Parcel reply = Parcel.obtain();
-            data.writeInt(i);
-            try {
-                retriever.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Failure retrieving array; only received " + i + " of " + itemCount, e);
-                return;
-            }
-            while (i < itemCount && reply.readInt() != 0) {
-                final T parcelable = reply.readParcelable(null);
-                mList.add(parcelable);
-
-                if (DEBUG) {
-                    Log.d(TAG, "Read extra #" + i + ": " + mList.get(mList.size() - 1));
-                }
-                i++;
-            }
-            reply.recycle();
-            data.recycle();
-        }
-    }
-
-    public List<T> getList() {
-        return mList;
-    }
-
-    /**
-     * Write this to another Parcel. Note that this discards the internal Parcel
-     * and should not be used anymore. This is so we can pass this to a Binder
-     * where we won't have a chance to call recycle on this.
-     */
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        final int itemCount = mList.size();
-        dest.writeInt(itemCount);
-        if (DEBUG) {
-            Log.d(TAG, "Writing " + itemCount + " items");
-        }
-        if (itemCount > 0) {
-            int i = 0;
-            while (i < itemCount && dest.dataSize() < MAX_IPC_SIZE) {
-                dest.writeInt(1);
-
-                final T parcelable = mList.get(i);
-                dest.writeParcelable(parcelable, flags);
-
-                if (DEBUG) {
-                    Log.d(TAG, "Wrote inline #" + i + ": " + mList.get(i));
-                }
-                i++;
-            }
-            if (i < itemCount) {
-                dest.writeInt(0);
-                Binder retriever = new Binder() {
-                    @Override
-                    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
-                            throws RemoteException {
-                        if (code != FIRST_CALL_TRANSACTION) {
-                            return super.onTransact(code, data, reply, flags);
-                        }
-                        int i = data.readInt();
-                        if (DEBUG) {
-                            Log.d(TAG, "Writing more @" + i + " of " + itemCount);
-                        }
-                        while (i < itemCount && reply.dataSize() < MAX_IPC_SIZE) {
-                            reply.writeInt(1);
-
-                            final T parcelable = mList.get(i);
-                            reply.writeParcelable(parcelable, flags);
-
-                            if (DEBUG) {
-                                Log.d(TAG, "Wrote extra #" + i + ": " + mList.get(i));
-                            }
-                            i++;
-                        }
-                        if (i < itemCount) {
-                            if (DEBUG) {
-                                Log.d(TAG, "Breaking @" + i + " of " + itemCount);
-                            }
-                            reply.writeInt(0);
-                        }
-                        return true;
-                    }
-                };
-                if (DEBUG) {
-                    Log.d(TAG, "Breaking @" + i + " of " + itemCount + ": retriever=" + retriever);
-                }
-                dest.writeStrongBinder(retriever);
-            }
-        }
-    }
-
-    @Override
-    public int describeContents() {
-        int contents = 0;
-        final List<T> list = getList();
-        for (int i = 0; i < list.size(); i++) {
-            contents |= list.get(i).describeContents();
-        }
-        return contents;
-    }
-
-    public static final Parcelable.Creator<MediaParceledListSlice> CREATOR =
-            new Parcelable.Creator<MediaParceledListSlice>() {
-        @Override
-        public MediaParceledListSlice createFromParcel(Parcel in) {
-            return new MediaParceledListSlice(in);
-        }
-
-        @Override
-        public MediaParceledListSlice[] newArray(int size) {
-            return new MediaParceledListSlice[size];
-        }
-    };
-}
diff --git a/packages/MediaComponents/apex/java/android/media/Rating.aidl b/packages/MediaComponents/apex/java/android/media/Rating.aidl
deleted file mode 100644
index 1dc336a..0000000
--- a/packages/MediaComponents/apex/java/android/media/Rating.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2013 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;
-
-parcelable Rating;
diff --git a/packages/MediaComponents/apex/java/android/media/Rating.java b/packages/MediaComponents/apex/java/android/media/Rating.java
deleted file mode 100644
index 04d5364..0000000
--- a/packages/MediaComponents/apex/java/android/media/Rating.java
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * Copyright (C) 2013 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 android.annotation.IntDef;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.Log;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * A class to encapsulate rating information used as content metadata.
- * A rating is defined by its rating style (see {@link #RATING_HEART},
- * {@link #RATING_THUMB_UP_DOWN}, {@link #RATING_3_STARS}, {@link #RATING_4_STARS},
- * {@link #RATING_5_STARS} or {@link #RATING_PERCENTAGE}) and the actual rating value (which may
- * be defined as "unrated"), both of which are defined when the rating instance is constructed
- * through one of the factory methods.
- */
-public final class Rating implements Parcelable {
-    private final static String TAG = "Rating";
-
-    /**
-     * @hide
-     */
-    @IntDef({RATING_NONE, RATING_HEART, RATING_THUMB_UP_DOWN, RATING_3_STARS, RATING_4_STARS,
-            RATING_5_STARS, RATING_PERCENTAGE})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface Style {}
-
-    /**
-     * @hide
-     */
-    @IntDef({RATING_3_STARS, RATING_4_STARS, RATING_5_STARS})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface StarStyle {}
-
-    /**
-     * Indicates a rating style is not supported. A Rating will never have this
-     * type, but can be used by other classes to indicate they do not support
-     * Rating.
-     */
-    public final static int RATING_NONE = 0;
-
-    /**
-     * A rating style with a single degree of rating, "heart" vs "no heart". Can be used to
-     * indicate the content referred to is a favorite (or not).
-     */
-    public final static int RATING_HEART = 1;
-
-    /**
-     * A rating style for "thumb up" vs "thumb down".
-     */
-    public final static int RATING_THUMB_UP_DOWN = 2;
-
-    /**
-     * A rating style with 0 to 3 stars.
-     */
-    public final static int RATING_3_STARS = 3;
-
-    /**
-     * A rating style with 0 to 4 stars.
-     */
-    public final static int RATING_4_STARS = 4;
-
-    /**
-     * A rating style with 0 to 5 stars.
-     */
-    public final static int RATING_5_STARS = 5;
-
-    /**
-     * A rating style expressed as a percentage.
-     */
-    public final static int RATING_PERCENTAGE = 6;
-
-    private final static float RATING_NOT_RATED = -1.0f;
-
-    private final int mRatingStyle;
-
-    private final float mRatingValue;
-
-    private Rating(@Style int ratingStyle, float rating) {
-        mRatingStyle = ratingStyle;
-        mRatingValue = rating;
-    }
-
-    @Override
-    public String toString() {
-        return "Rating:style=" + mRatingStyle + " rating="
-                + (mRatingValue < 0.0f ? "unrated" : String.valueOf(mRatingValue));
-    }
-
-    @Override
-    public int describeContents() {
-        return mRatingStyle;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mRatingStyle);
-        dest.writeFloat(mRatingValue);
-    }
-
-    public static final Parcelable.Creator<Rating> CREATOR
-            = new Parcelable.Creator<Rating>() {
-        /**
-         * Rebuilds a Rating previously stored with writeToParcel().
-         * @param p    Parcel object to read the Rating from
-         * @return a new Rating created from the data in the parcel
-         */
-        @Override
-        public Rating createFromParcel(Parcel p) {
-            return new Rating(p.readInt(), p.readFloat());
-        }
-
-        @Override
-        public Rating[] newArray(int size) {
-            return new Rating[size];
-        }
-    };
-
-    /**
-     * Return a Rating instance with no rating.
-     * Create and return a new Rating instance with no rating known for the given
-     * rating style.
-     * @param ratingStyle one of {@link #RATING_HEART}, {@link #RATING_THUMB_UP_DOWN},
-     *    {@link #RATING_3_STARS}, {@link #RATING_4_STARS}, {@link #RATING_5_STARS},
-     *    or {@link #RATING_PERCENTAGE}.
-     * @return null if an invalid rating style is passed, a new Rating instance otherwise.
-     */
-    public static Rating newUnratedRating(@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 Rating(ratingStyle, RATING_NOT_RATED);
-            default:
-                return null;
-        }
-    }
-
-    /**
-     * Return a Rating instance with a heart-based rating.
-     * Create and return a new Rating instance with a rating style of {@link #RATING_HEART},
-     * and a heart-based rating.
-     * @param hasHeart true for a "heart selected" rating, false for "heart unselected".
-     * @return a new Rating instance.
-     */
-    public static Rating newHeartRating(boolean hasHeart) {
-        return new Rating(RATING_HEART, hasHeart ? 1.0f : 0.0f);
-    }
-
-    /**
-     * Return a Rating instance with a thumb-based rating.
-     * Create and return a new Rating instance with a {@link #RATING_THUMB_UP_DOWN}
-     * rating style, and a "thumb up" or "thumb down" rating.
-     * @param thumbIsUp true for a "thumb up" rating, false for "thumb down".
-     * @return a new Rating instance.
-     */
-    public static Rating newThumbRating(boolean thumbIsUp) {
-        return new Rating(RATING_THUMB_UP_DOWN, thumbIsUp ? 1.0f : 0.0f);
-    }
-
-    /**
-     * Return a Rating instance with a star-based rating.
-     * Create and return a new Rating instance with one of the star-base rating styles
-     * and the given integer or fractional number of stars. Non integer values can for instance
-     * be used to represent an average rating value, which might not be an integer number of stars.
-     * @param starRatingStyle one of {@link #RATING_3_STARS}, {@link #RATING_4_STARS},
-     *     {@link #RATING_5_STARS}.
-     * @param starRating a number ranging from 0.0f to 3.0f, 4.0f or 5.0f according to
-     *     the rating style.
-     * @return null if the rating style is invalid, or the rating is out of range,
-     *     a new Rating instance otherwise.
-     */
-    public static Rating newStarRating(@StarStyle int starRatingStyle, float starRating) {
-        float maxRating = -1.0f;
-        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 Rating(starRatingStyle, starRating);
-    }
-
-    /**
-     * Return a Rating instance with a percentage-based rating.
-     * Create and return a new Rating instance with a {@link #RATING_PERCENTAGE}
-     * rating style, and a rating of the given percentage.
-     * @param percent the value of the rating
-     * @return null if the rating is out of range, a new Rating instance otherwise.
-     */
-    public static Rating newPercentageRating(float percent) {
-        if ((percent < 0.0f) || (percent > 100.0f)) {
-            Log.e(TAG, "Invalid percentage-based rating value");
-            return null;
-        } else {
-            return new Rating(RATING_PERCENTAGE, percent);
-        }
-    }
-
-    /**
-     * Return whether there is a rating value available.
-     * @return true if the instance was not created with {@link #newUnratedRating(int)}.
-     */
-    public boolean isRated() {
-        return mRatingValue >= 0.0f;
-    }
-
-    /**
-     * Return the rating style.
-     * @return one of {@link #RATING_HEART}, {@link #RATING_THUMB_UP_DOWN},
-     *    {@link #RATING_3_STARS}, {@link #RATING_4_STARS}, {@link #RATING_5_STARS},
-     *    or {@link #RATING_PERCENTAGE}.
-     */
-    @Style
-    public int getRatingStyle() {
-        return mRatingStyle;
-    }
-
-    /**
-     * Return whether the rating is "heart selected".
-     * @return true if the rating is "heart selected", false if the rating is "heart unselected",
-     *    if the rating style is not {@link #RATING_HEART} or if it is unrated.
-     */
-    public boolean hasHeart() {
-        if (mRatingStyle != RATING_HEART) {
-            return false;
-        } else {
-            return (mRatingValue == 1.0f);
-        }
-    }
-
-    /**
-     * Return whether the rating is "thumb up".
-     * @return true if the rating is "thumb up", false if the rating is "thumb down",
-     *    if the rating style is not {@link #RATING_THUMB_UP_DOWN} or if it is unrated.
-     */
-    public boolean isThumbUp() {
-        if (mRatingStyle != RATING_THUMB_UP_DOWN) {
-            return false;
-        } else {
-            return (mRatingValue == 1.0f);
-        }
-    }
-
-    /**
-     * Return the star-based rating value.
-     * @return a rating value greater or equal to 0.0f, or a negative value if the rating style is
-     *    not star-based, or if it is unrated.
-     */
-    public float getStarRating() {
-        switch (mRatingStyle) {
-            case RATING_3_STARS:
-            case RATING_4_STARS:
-            case RATING_5_STARS:
-                if (isRated()) {
-                    return mRatingValue;
-                }
-            default:
-                return -1.0f;
-        }
-    }
-
-    /**
-     * Return the percentage-based rating value.
-     * @return a rating value greater or equal to 0.0f, or a negative value if the rating style is
-     *    not percentage-based, or if it is unrated.
-     */
-    public float getPercentRating() {
-        if ((mRatingStyle != RATING_PERCENTAGE) || !isRated()) {
-            return -1.0f;
-        } else {
-            return mRatingValue;
-        }
-    }
-}
diff --git a/packages/MediaComponents/apex/java/android/media/VolumeProvider.java b/packages/MediaComponents/apex/java/android/media/VolumeProvider.java
deleted file mode 100644
index 1c017c5..0000000
--- a/packages/MediaComponents/apex/java/android/media/VolumeProvider.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2014 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 android.annotation.IntDef;
-import android.media.session.MediaSession;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Handles requests to adjust or set the volume on a session. This is also used
- * to push volume updates back to the session. The provider must call
- * {@link #setCurrentVolume(int)} each time the volume being provided changes.
- * <p>
- * You can set a volume provider on a session by calling
- * {@link MediaSession#setPlaybackToRemote}.
- */
-public abstract class VolumeProvider {
-
-    /**
-     * @hide
-     */
-    @IntDef({VOLUME_CONTROL_FIXED, VOLUME_CONTROL_RELATIVE, VOLUME_CONTROL_ABSOLUTE})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface ControlType {}
-
-    /**
-     * The volume is fixed and can not be modified. Requests to change volume
-     * should be ignored.
-     */
-    public static final int VOLUME_CONTROL_FIXED = 0;
-
-    /**
-     * The volume control uses relative adjustment via
-     * {@link #onAdjustVolume(int)}. Attempts to set the volume to a specific
-     * value should be ignored.
-     */
-    public static final int VOLUME_CONTROL_RELATIVE = 1;
-
-    /**
-     * The volume control uses an absolute value. It may be adjusted using
-     * {@link #onAdjustVolume(int)} or set directly using
-     * {@link #onSetVolumeTo(int)}.
-     */
-    public static final int VOLUME_CONTROL_ABSOLUTE = 2;
-
-    private final int mControlType;
-    private final int mMaxVolume;
-    private int mCurrentVolume;
-    private Callback mCallback;
-
-    /**
-     * Create a new volume provider for handling volume events. You must specify
-     * the type of volume control, the maximum volume that can be used, and the
-     * current volume on the output.
-     *
-     * @param volumeControl The method for controlling volume that is used by
-     *            this provider.
-     * @param maxVolume The maximum allowed volume.
-     * @param currentVolume The current volume on the output.
-     */
-    public VolumeProvider(@ControlType int volumeControl, int maxVolume, int currentVolume) {
-        mControlType = volumeControl;
-        mMaxVolume = maxVolume;
-        mCurrentVolume = currentVolume;
-    }
-
-    /**
-     * Get the volume control type that this volume provider uses.
-     *
-     * @return The volume control type for this volume provider
-     */
-    @ControlType
-    public final int getVolumeControl() {
-        return mControlType;
-    }
-
-    /**
-     * Get the maximum volume this provider allows.
-     *
-     * @return The max allowed volume.
-     */
-    public final int getMaxVolume() {
-        return mMaxVolume;
-    }
-
-    /**
-     * Gets the current volume. This will be the last value set by
-     * {@link #setCurrentVolume(int)}.
-     *
-     * @return The current volume.
-     */
-    public final int getCurrentVolume() {
-        return mCurrentVolume;
-    }
-
-    /**
-     * Notify the system that the current volume has been changed. This must be
-     * called every time the volume changes to ensure it is displayed properly.
-     *
-     * @param currentVolume The current volume on the output.
-     */
-    public final void setCurrentVolume(int currentVolume) {
-        mCurrentVolume = currentVolume;
-        if (mCallback != null) {
-            mCallback.onVolumeChanged(this);
-        }
-    }
-
-    /**
-     * Override to handle requests to set the volume of the current output.
-     * After the volume has been modified {@link #setCurrentVolume} must be
-     * called to notify the system.
-     *
-     * @param volume The volume to set the output to.
-     */
-    public void onSetVolumeTo(int volume) {
-    }
-
-    /**
-     * Override to handle requests to adjust the volume of the current output.
-     * Direction will be one of {@link AudioManager#ADJUST_LOWER},
-     * {@link AudioManager#ADJUST_RAISE}, {@link AudioManager#ADJUST_SAME}.
-     * After the volume has been modified {@link #setCurrentVolume} must be
-     * called to notify the system.
-     *
-     * @param direction The direction to change the volume in.
-     */
-    public void onAdjustVolume(int direction) {
-    }
-
-    /**
-     * Sets a callback to receive volume changes.
-     * @hide
-     */
-    public void setCallback(Callback callback) {
-        mCallback = callback;
-    }
-
-    /**
-     * Listens for changes to the volume.
-     * @hide
-     */
-    public static abstract class Callback {
-        public abstract void onVolumeChanged(VolumeProvider volumeProvider);
-    }
-}
diff --git a/packages/MediaComponents/apex/java/android/media/browse/MediaBrowser.aidl b/packages/MediaComponents/apex/java/android/media/browse/MediaBrowser.aidl
deleted file mode 100644
index 782e094..0000000
--- a/packages/MediaComponents/apex/java/android/media/browse/MediaBrowser.aidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/* Copyright 2014, 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.browse;
-
-parcelable MediaBrowser.MediaItem;
\ No newline at end of file
diff --git a/packages/MediaComponents/apex/java/android/media/browse/MediaBrowser.java b/packages/MediaComponents/apex/java/android/media/browse/MediaBrowser.java
deleted file mode 100644
index b1b14c6..0000000
--- a/packages/MediaComponents/apex/java/android/media/browse/MediaBrowser.java
+++ /dev/null
@@ -1,1171 +0,0 @@
-/*
- * Copyright (C) 2014 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.browse;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.media.MediaDescription;
-import android.media.MediaParceledListSlice;
-import android.media.session.MediaController;
-import android.media.session.MediaSession;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.service.media.IMediaBrowserService;
-import android.service.media.IMediaBrowserServiceCallbacks;
-import android.service.media.MediaBrowserService;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.Log;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map.Entry;
-
-/**
- * Browses media content offered by a link MediaBrowserService.
- * <p>
- * This object is not thread-safe. All calls should happen on the thread on which the browser
- * was constructed.
- * </p>
- * <h3>Standard Extra Data</h3>
- *
- * <p>These are the current standard fields that can be used as extra data via
- * {@link #subscribe(String, Bundle, SubscriptionCallback)},
- * {@link #unsubscribe(String, SubscriptionCallback)}, and
- * {@link SubscriptionCallback#onChildrenLoaded(String, List, Bundle)}.
- *
- * <ul>
- *     <li> {@link #EXTRA_PAGE}
- *     <li> {@link #EXTRA_PAGE_SIZE}
- * </ul>
- */
-public final class MediaBrowser {
-    private static final String TAG = "MediaBrowser";
-    private static final boolean DBG = false;
-
-    /**
-     * Used as an int extra field to denote the page number to subscribe.
-     * The value of {@code EXTRA_PAGE} should be greater than or equal to 0.
-     *
-     * @see #EXTRA_PAGE_SIZE
-     */
-    public static final String EXTRA_PAGE = "android.media.browse.extra.PAGE";
-
-    /**
-     * Used as an int extra field to denote the number of media items in a page.
-     * The value of {@code EXTRA_PAGE_SIZE} should be greater than or equal to 1.
-     *
-     * @see #EXTRA_PAGE
-     */
-    public static final String EXTRA_PAGE_SIZE = "android.media.browse.extra.PAGE_SIZE";
-
-    private static final int CONNECT_STATE_DISCONNECTING = 0;
-    private static final int CONNECT_STATE_DISCONNECTED = 1;
-    private static final int CONNECT_STATE_CONNECTING = 2;
-    private static final int CONNECT_STATE_CONNECTED = 3;
-    private static final int CONNECT_STATE_SUSPENDED = 4;
-
-    private final Context mContext;
-    private final ComponentName mServiceComponent;
-    private final ConnectionCallback mCallback;
-    private final Bundle mRootHints;
-    private final Handler mHandler = new Handler();
-    private final ArrayMap<String, Subscription> mSubscriptions = new ArrayMap<>();
-
-    private volatile int mState = CONNECT_STATE_DISCONNECTED;
-    private volatile String mRootId;
-    private volatile MediaSession.Token mMediaSessionToken;
-    private volatile Bundle mExtras;
-
-    private MediaServiceConnection mServiceConnection;
-    private IMediaBrowserService mServiceBinder;
-    private IMediaBrowserServiceCallbacks mServiceCallbacks;
-
-    /**
-     * Creates a media browser for the specified media browser service.
-     *
-     * @param context The context.
-     * @param serviceComponent The component name of the media browser service.
-     * @param callback The connection callback.
-     * @param rootHints An optional bundle of service-specific arguments to send
-     * to the media browser service when connecting and retrieving the root id
-     * for browsing, or null if none. The contents of this bundle may affect
-     * the information returned when browsing.
-     * @see android.service.media.MediaBrowserService.BrowserRoot#EXTRA_RECENT
-     * @see android.service.media.MediaBrowserService.BrowserRoot#EXTRA_OFFLINE
-     * @see android.service.media.MediaBrowserService.BrowserRoot#EXTRA_SUGGESTED
-     */
-    public MediaBrowser(Context context, ComponentName serviceComponent,
-            ConnectionCallback callback, Bundle rootHints) {
-        if (context == null) {
-            throw new IllegalArgumentException("context must not be null");
-        }
-        if (serviceComponent == null) {
-            throw new IllegalArgumentException("service component must not be null");
-        }
-        if (callback == null) {
-            throw new IllegalArgumentException("connection callback must not be null");
-        }
-        mContext = context;
-        mServiceComponent = serviceComponent;
-        mCallback = callback;
-        mRootHints = rootHints == null ? null : new Bundle(rootHints);
-    }
-
-    /**
-     * Connects to the media browser service.
-     * <p>
-     * The connection callback specified in the constructor will be invoked
-     * when the connection completes or fails.
-     * </p>
-     */
-    public void connect() {
-        if (mState != CONNECT_STATE_DISCONNECTING && mState != CONNECT_STATE_DISCONNECTED) {
-            throw new IllegalStateException("connect() called while neither disconnecting nor "
-                    + "disconnected (state=" + getStateLabel(mState) + ")");
-        }
-
-        mState = CONNECT_STATE_CONNECTING;
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                if (mState == CONNECT_STATE_DISCONNECTING) {
-                    return;
-                }
-                mState = CONNECT_STATE_CONNECTING;
-                // TODO: remove this extra check.
-                if (DBG) {
-                    if (mServiceConnection != null) {
-                        throw new RuntimeException("mServiceConnection should be null. Instead it"
-                                + " is " + mServiceConnection);
-                    }
-                }
-                if (mServiceBinder != null) {
-                    throw new RuntimeException("mServiceBinder should be null. Instead it is "
-                            + mServiceBinder);
-                }
-                if (mServiceCallbacks != null) {
-                    throw new RuntimeException("mServiceCallbacks should be null. Instead it is "
-                            + mServiceCallbacks);
-                }
-
-                final Intent intent = new Intent(MediaBrowserService.SERVICE_INTERFACE);
-                intent.setComponent(mServiceComponent);
-
-                mServiceConnection = new MediaServiceConnection();
-
-                boolean bound = false;
-                try {
-                    bound = mContext.bindService(intent, mServiceConnection,
-                            Context.BIND_AUTO_CREATE);
-                } catch (Exception ex) {
-                    Log.e(TAG, "Failed binding to service " + mServiceComponent);
-                }
-
-                if (!bound) {
-                    // Tell them that it didn't work.
-                    forceCloseConnection();
-                    mCallback.onConnectionFailed();
-                }
-
-                if (DBG) {
-                    Log.d(TAG, "connect...");
-                    dump();
-                }
-            }
-        });
-    }
-
-    /**
-     * Disconnects from the media browser service.
-     * After this, no more callbacks will be received.
-     */
-    public void disconnect() {
-        // It's ok to call this any state, because allowing this lets apps not have
-        // to check isConnected() unnecessarily. They won't appreciate the extra
-        // assertions for this. We do everything we can here to go back to a sane state.
-        mState = CONNECT_STATE_DISCONNECTING;
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                // connect() could be called before this. Then we will disconnect and reconnect.
-                if (mServiceCallbacks != null) {
-                    try {
-                        mServiceBinder.disconnect(mServiceCallbacks);
-                    } catch (RemoteException ex) {
-                        // We are disconnecting anyway. Log, just for posterity but it's not
-                        // a big problem.
-                        Log.w(TAG, "RemoteException during connect for " + mServiceComponent);
-                    }
-                }
-                int state = mState;
-                forceCloseConnection();
-                // If the state was not CONNECT_STATE_DISCONNECTING, keep the state so that
-                // the operation came after disconnect() can be handled properly.
-                if (state != CONNECT_STATE_DISCONNECTING) {
-                    mState = state;
-                }
-                if (DBG) {
-                    Log.d(TAG, "disconnect...");
-                    dump();
-                }
-            }
-        });
-    }
-
-    /**
-     * Null out the variables and unbind from the service. This doesn't include
-     * calling disconnect on the service, because we only try to do that in the
-     * clean shutdown cases.
-     * <p>
-     * Everywhere that calls this EXCEPT for disconnect() should follow it with
-     * a call to mCallback.onConnectionFailed(). Disconnect doesn't do that callback
-     * for a clean shutdown, but everywhere else is a dirty shutdown and should
-     * notify the app.
-     * <p>
-     * Also, mState should be updated properly. Mostly it should be CONNECT_STATE_DIACONNECTED
-     * except for disconnect().
-     */
-    private void forceCloseConnection() {
-        if (mServiceConnection != null) {
-            try {
-                mContext.unbindService(mServiceConnection);
-            } catch (IllegalArgumentException e) {
-                if (DBG) {
-                    Log.d(TAG, "unbindService failed", e);
-                }
-            }
-        }
-        mState = CONNECT_STATE_DISCONNECTED;
-        mServiceConnection = null;
-        mServiceBinder = null;
-        mServiceCallbacks = null;
-        mRootId = null;
-        mMediaSessionToken = null;
-    }
-
-    /**
-     * Returns whether the browser is connected to the service.
-     */
-    public boolean isConnected() {
-        return mState == CONNECT_STATE_CONNECTED;
-    }
-
-    /**
-     * Gets the service component that the media browser is connected to.
-     */
-    public @NonNull ComponentName getServiceComponent() {
-        if (!isConnected()) {
-            throw new IllegalStateException("getServiceComponent() called while not connected" +
-                    " (state=" + mState + ")");
-        }
-        return mServiceComponent;
-    }
-
-    /**
-     * Gets the root id.
-     * <p>
-     * Note that the root id may become invalid or change when the
-     * browser is disconnected.
-     * </p>
-     *
-     * @throws IllegalStateException if not connected.
-     */
-    public @NonNull String getRoot() {
-        if (!isConnected()) {
-            throw new IllegalStateException("getRoot() called while not connected (state="
-                    + getStateLabel(mState) + ")");
-        }
-        return mRootId;
-    }
-
-    /**
-     * Gets any extras for the media service.
-     *
-     * @throws IllegalStateException if not connected.
-     */
-    public @Nullable Bundle getExtras() {
-        if (!isConnected()) {
-            throw new IllegalStateException("getExtras() called while not connected (state="
-                    + getStateLabel(mState) + ")");
-        }
-        return mExtras;
-    }
-
-    /**
-     * Gets the media session token associated with the media browser.
-     * <p>
-     * Note that the session token may become invalid or change when the
-     * browser is disconnected.
-     * </p>
-     *
-     * @return The session token for the browser, never null.
-     *
-     * @throws IllegalStateException if not connected.
-     */
-     public @NonNull MediaSession.Token getSessionToken() {
-        if (!isConnected()) {
-            throw new IllegalStateException("getSessionToken() called while not connected (state="
-                    + mState + ")");
-        }
-        return mMediaSessionToken;
-    }
-
-    /**
-     * Queries for information about the media items that are contained within
-     * the specified id and subscribes to receive updates when they change.
-     * <p>
-     * The list of subscriptions is maintained even when not connected and is
-     * restored after the reconnection. It is ok to subscribe while not connected
-     * but the results will not be returned until the connection completes.
-     * </p>
-     * <p>
-     * If the id is already subscribed with a different callback then the new
-     * callback will replace the previous one and the child data will be
-     * reloaded.
-     * </p>
-     *
-     * @param parentId The id of the parent media item whose list of children
-     *            will be subscribed.
-     * @param callback The callback to receive the list of children.
-     */
-    public void subscribe(@NonNull String parentId, @NonNull SubscriptionCallback callback) {
-        subscribeInternal(parentId, null, callback);
-    }
-
-    /**
-     * Queries with service-specific arguments for information about the media items
-     * that are contained within the specified id and subscribes to receive updates
-     * when they change.
-     * <p>
-     * The list of subscriptions is maintained even when not connected and is
-     * restored after the reconnection. It is ok to subscribe while not connected
-     * but the results will not be returned until the connection completes.
-     * </p>
-     * <p>
-     * If the id is already subscribed with a different callback then the new
-     * callback will replace the previous one and the child data will be
-     * reloaded.
-     * </p>
-     *
-     * @param parentId The id of the parent media item whose list of children
-     *            will be subscribed.
-     * @param options The bundle of service-specific arguments to send to the media
-     *            browser service. The contents of this bundle may affect the
-     *            information returned when browsing.
-     * @param callback The callback to receive the list of children.
-     */
-    public void subscribe(@NonNull String parentId, @NonNull Bundle options,
-            @NonNull SubscriptionCallback callback) {
-        if (options == null) {
-            throw new IllegalArgumentException("options cannot be null");
-        }
-        subscribeInternal(parentId, new Bundle(options), callback);
-    }
-
-    /**
-     * Unsubscribes for changes to the children of the specified media id.
-     * <p>
-     * The query callback will no longer be invoked for results associated with
-     * this id once this method returns.
-     * </p>
-     *
-     * @param parentId The id of the parent media item whose list of children
-     *            will be unsubscribed.
-     */
-    public void unsubscribe(@NonNull String parentId) {
-        unsubscribeInternal(parentId, null);
-    }
-
-    /**
-     * Unsubscribes for changes to the children of the specified media id through a callback.
-     * <p>
-     * The query callback will no longer be invoked for results associated with
-     * this id once this method returns.
-     * </p>
-     *
-     * @param parentId The id of the parent media item whose list of children
-     *            will be unsubscribed.
-     * @param callback A callback sent to the media browser service to subscribe.
-     */
-    public void unsubscribe(@NonNull String parentId, @NonNull SubscriptionCallback callback) {
-        if (callback == null) {
-            throw new IllegalArgumentException("callback cannot be null");
-        }
-        unsubscribeInternal(parentId, callback);
-    }
-
-    /**
-     * Retrieves a specific {@link MediaItem} from the connected service. Not
-     * all services may support this, so falling back to subscribing to the
-     * parent's id should be used when unavailable.
-     *
-     * @param mediaId The id of the item to retrieve.
-     * @param cb The callback to receive the result on.
-     */
-    public void getItem(final @NonNull String mediaId, @NonNull final ItemCallback cb) {
-        if (TextUtils.isEmpty(mediaId)) {
-            throw new IllegalArgumentException("mediaId cannot be empty.");
-        }
-        if (cb == null) {
-            throw new IllegalArgumentException("cb cannot be null.");
-        }
-        if (mState != CONNECT_STATE_CONNECTED) {
-            Log.i(TAG, "Not connected, unable to retrieve the MediaItem.");
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    cb.onError(mediaId);
-                }
-            });
-            return;
-        }
-        ResultReceiver receiver = new ResultReceiver(mHandler) {
-            @Override
-            protected void onReceiveResult(int resultCode, Bundle resultData) {
-                if (!isConnected()) {
-                    return;
-                }
-                if (resultCode != 0 || resultData == null
-                        || !resultData.containsKey(MediaBrowserService.KEY_MEDIA_ITEM)) {
-                    cb.onError(mediaId);
-                    return;
-                }
-                Parcelable item = resultData.getParcelable(MediaBrowserService.KEY_MEDIA_ITEM);
-                if (item != null && !(item instanceof MediaItem)) {
-                    cb.onError(mediaId);
-                    return;
-                }
-                cb.onItemLoaded((MediaItem)item);
-            }
-        };
-        try {
-            mServiceBinder.getMediaItem(mediaId, receiver, mServiceCallbacks);
-        } catch (RemoteException e) {
-            Log.i(TAG, "Remote error getting media item.");
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    cb.onError(mediaId);
-                }
-            });
-        }
-    }
-
-    private void subscribeInternal(String parentId, Bundle options, SubscriptionCallback callback) {
-        // Check arguments.
-        if (TextUtils.isEmpty(parentId)) {
-            throw new IllegalArgumentException("parentId cannot be empty.");
-        }
-        if (callback == null) {
-            throw new IllegalArgumentException("callback cannot be null");
-        }
-        // Update or create the subscription.
-        Subscription sub = mSubscriptions.get(parentId);
-        if (sub == null) {
-            sub = new Subscription();
-            mSubscriptions.put(parentId, sub);
-        }
-        sub.putCallback(mContext, options, callback);
-
-        // If we are connected, tell the service that we are watching. If we aren't connected,
-        // the service will be told when we connect.
-        if (isConnected()) {
-            try {
-                if (options == null) {
-                    mServiceBinder.addSubscriptionDeprecated(parentId, mServiceCallbacks);
-                }
-                mServiceBinder.addSubscription(parentId, callback.mToken, options,
-                        mServiceCallbacks);
-            } catch (RemoteException ex) {
-                // Process is crashing. We will disconnect, and upon reconnect we will
-                // automatically reregister. So nothing to do here.
-                Log.d(TAG, "addSubscription failed with RemoteException parentId=" + parentId);
-            }
-        }
-    }
-
-    private void unsubscribeInternal(String parentId, SubscriptionCallback callback) {
-        // Check arguments.
-        if (TextUtils.isEmpty(parentId)) {
-            throw new IllegalArgumentException("parentId cannot be empty.");
-        }
-
-        Subscription sub = mSubscriptions.get(parentId);
-        if (sub == null) {
-            return;
-        }
-        // Tell the service if necessary.
-        try {
-            if (callback == null) {
-                if (isConnected()) {
-                    mServiceBinder.removeSubscriptionDeprecated(parentId, mServiceCallbacks);
-                    mServiceBinder.removeSubscription(parentId, null, mServiceCallbacks);
-                }
-            } else {
-                final List<SubscriptionCallback> callbacks = sub.getCallbacks();
-                final List<Bundle> optionsList = sub.getOptionsList();
-                for (int i = callbacks.size() - 1; i >= 0; --i) {
-                    if (callbacks.get(i) == callback) {
-                        if (isConnected()) {
-                            mServiceBinder.removeSubscription(
-                                    parentId, callback.mToken, mServiceCallbacks);
-                        }
-                        callbacks.remove(i);
-                        optionsList.remove(i);
-                    }
-                }
-            }
-        } catch (RemoteException ex) {
-            // Process is crashing. We will disconnect, and upon reconnect we will
-            // automatically reregister. So nothing to do here.
-            Log.d(TAG, "removeSubscription failed with RemoteException parentId=" + parentId);
-        }
-
-        if (sub.isEmpty() || callback == null) {
-            mSubscriptions.remove(parentId);
-        }
-    }
-
-    /**
-     * For debugging.
-     */
-    private static String getStateLabel(int state) {
-        switch (state) {
-            case CONNECT_STATE_DISCONNECTING:
-                return "CONNECT_STATE_DISCONNECTING";
-            case CONNECT_STATE_DISCONNECTED:
-                return "CONNECT_STATE_DISCONNECTED";
-            case CONNECT_STATE_CONNECTING:
-                return "CONNECT_STATE_CONNECTING";
-            case CONNECT_STATE_CONNECTED:
-                return "CONNECT_STATE_CONNECTED";
-            case CONNECT_STATE_SUSPENDED:
-                return "CONNECT_STATE_SUSPENDED";
-            default:
-                return "UNKNOWN/" + state;
-        }
-    }
-
-    private final void onServiceConnected(final IMediaBrowserServiceCallbacks callback,
-            final String root, final MediaSession.Token session, final Bundle extra) {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                // Check to make sure there hasn't been a disconnect or a different
-                // ServiceConnection.
-                if (!isCurrent(callback, "onConnect")) {
-                    return;
-                }
-                // Don't allow them to call us twice.
-                if (mState != CONNECT_STATE_CONNECTING) {
-                    Log.w(TAG, "onConnect from service while mState="
-                            + getStateLabel(mState) + "... ignoring");
-                    return;
-                }
-                mRootId = root;
-                mMediaSessionToken = session;
-                mExtras = extra;
-                mState = CONNECT_STATE_CONNECTED;
-
-                if (DBG) {
-                    Log.d(TAG, "ServiceCallbacks.onConnect...");
-                    dump();
-                }
-                mCallback.onConnected();
-
-                // we may receive some subscriptions before we are connected, so re-subscribe
-                // everything now
-                for (Entry<String, Subscription> subscriptionEntry : mSubscriptions.entrySet()) {
-                    String id = subscriptionEntry.getKey();
-                    Subscription sub = subscriptionEntry.getValue();
-                    List<SubscriptionCallback> callbackList = sub.getCallbacks();
-                    List<Bundle> optionsList = sub.getOptionsList();
-                    for (int i = 0; i < callbackList.size(); ++i) {
-                        try {
-                            mServiceBinder.addSubscription(id, callbackList.get(i).mToken,
-                                    optionsList.get(i), mServiceCallbacks);
-                        } catch (RemoteException ex) {
-                            // Process is crashing. We will disconnect, and upon reconnect we will
-                            // automatically reregister. So nothing to do here.
-                            Log.d(TAG, "addSubscription failed with RemoteException parentId="
-                                    + id);
-                        }
-                    }
-                }
-            }
-        });
-    }
-
-    private final void onConnectionFailed(final IMediaBrowserServiceCallbacks callback) {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                Log.e(TAG, "onConnectFailed for " + mServiceComponent);
-
-                // Check to make sure there hasn't been a disconnect or a different
-                // ServiceConnection.
-                if (!isCurrent(callback, "onConnectFailed")) {
-                    return;
-                }
-                // Don't allow them to call us twice.
-                if (mState != CONNECT_STATE_CONNECTING) {
-                    Log.w(TAG, "onConnect from service while mState="
-                            + getStateLabel(mState) + "... ignoring");
-                    return;
-                }
-
-                // Clean up
-                forceCloseConnection();
-
-                // Tell the app.
-                mCallback.onConnectionFailed();
-            }
-        });
-    }
-
-    private final void onLoadChildren(final IMediaBrowserServiceCallbacks callback,
-            final String parentId, final MediaParceledListSlice list, final Bundle options) {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                // Check that there hasn't been a disconnect or a different
-                // ServiceConnection.
-                if (!isCurrent(callback, "onLoadChildren")) {
-                    return;
-                }
-
-                if (DBG) {
-                    Log.d(TAG, "onLoadChildren for " + mServiceComponent + " id=" + parentId);
-                }
-
-                // Check that the subscription is still subscribed.
-                final Subscription subscription = mSubscriptions.get(parentId);
-                if (subscription != null) {
-                    // Tell the app.
-                    SubscriptionCallback subscriptionCallback =
-                            subscription.getCallback(mContext, options);
-                    if (subscriptionCallback != null) {
-                        List<MediaItem> data = list == null ? null : list.getList();
-                        if (options == null) {
-                            if (data == null) {
-                                subscriptionCallback.onError(parentId);
-                            } else {
-                                subscriptionCallback.onChildrenLoaded(parentId, data);
-                            }
-                        } else {
-                            if (data == null) {
-                                subscriptionCallback.onError(parentId, options);
-                            } else {
-                                subscriptionCallback.onChildrenLoaded(parentId, data, options);
-                            }
-                        }
-                        return;
-                    }
-                }
-                if (DBG) {
-                    Log.d(TAG, "onLoadChildren for id that isn't subscribed id=" + parentId);
-                }
-            }
-        });
-    }
-
-    /**
-     * Return true if {@code callback} is the current ServiceCallbacks. Also logs if it's not.
-     */
-    private boolean isCurrent(IMediaBrowserServiceCallbacks callback, String funcName) {
-        if (mServiceCallbacks != callback || mState == CONNECT_STATE_DISCONNECTING
-                || mState == CONNECT_STATE_DISCONNECTED) {
-            if (mState != CONNECT_STATE_DISCONNECTING && mState != CONNECT_STATE_DISCONNECTED) {
-                Log.i(TAG, funcName + " for " + mServiceComponent + " with mServiceConnection="
-                        + mServiceCallbacks + " this=" + this);
-            }
-            return false;
-        }
-        return true;
-    }
-
-    private ServiceCallbacks getNewServiceCallbacks() {
-        return new ServiceCallbacks(this);
-    }
-
-    /**
-     * Log internal state.
-     * @hide
-     */
-    void dump() {
-        Log.d(TAG, "MediaBrowser...");
-        Log.d(TAG, "  mServiceComponent=" + mServiceComponent);
-        Log.d(TAG, "  mCallback=" + mCallback);
-        Log.d(TAG, "  mRootHints=" + mRootHints);
-        Log.d(TAG, "  mState=" + getStateLabel(mState));
-        Log.d(TAG, "  mServiceConnection=" + mServiceConnection);
-        Log.d(TAG, "  mServiceBinder=" + mServiceBinder);
-        Log.d(TAG, "  mServiceCallbacks=" + mServiceCallbacks);
-        Log.d(TAG, "  mRootId=" + mRootId);
-        Log.d(TAG, "  mMediaSessionToken=" + mMediaSessionToken);
-    }
-
-    /**
-     * A class with information on a single media item for use in browsing/searching media.
-     * MediaItems are application dependent so we cannot guarantee that they contain the
-     * right values.
-     */
-    public static class MediaItem implements Parcelable {
-        private final int mFlags;
-        private final MediaDescription mDescription;
-
-        /** @hide */
-        @Retention(RetentionPolicy.SOURCE)
-        @IntDef(flag=true, value = { FLAG_BROWSABLE, FLAG_PLAYABLE })
-        public @interface Flags { }
-
-        /**
-         * Flag: Indicates that the item has children of its own.
-         */
-        public static final int FLAG_BROWSABLE = 1 << 0;
-
-        /**
-         * Flag: Indicates that the item is playable.
-         * <p>
-         * The id of this item may be passed to
-         * {@link MediaController.TransportControls#playFromMediaId(String, Bundle)}
-         * to start playing it.
-         * </p>
-         */
-        public static final int FLAG_PLAYABLE = 1 << 1;
-
-        /**
-         * Create a new MediaItem for use in browsing media.
-         * @param description The description of the media, which must include a
-         *            media id.
-         * @param flags The flags for this item.
-         */
-        public MediaItem(@NonNull MediaDescription description, @Flags int flags) {
-            if (description == null) {
-                throw new IllegalArgumentException("description cannot be null");
-            }
-            if (TextUtils.isEmpty(description.getMediaId())) {
-                throw new IllegalArgumentException("description must have a non-empty media id");
-            }
-            mFlags = flags;
-            mDescription = description;
-        }
-
-        /**
-         * Private constructor.
-         */
-        private MediaItem(Parcel in) {
-            mFlags = in.readInt();
-            mDescription = MediaDescription.CREATOR.createFromParcel(in);
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeInt(mFlags);
-            mDescription.writeToParcel(out, flags);
-        }
-
-        @Override
-        public String toString() {
-            final StringBuilder sb = new StringBuilder("MediaItem{");
-            sb.append("mFlags=").append(mFlags);
-            sb.append(", mDescription=").append(mDescription);
-            sb.append('}');
-            return sb.toString();
-        }
-
-        public static final Parcelable.Creator<MediaItem> CREATOR =
-                new Parcelable.Creator<MediaItem>() {
-                    @Override
-                    public MediaItem createFromParcel(Parcel in) {
-                        return new MediaItem(in);
-                    }
-
-                    @Override
-                    public MediaItem[] newArray(int size) {
-                        return new MediaItem[size];
-                    }
-                };
-
-        /**
-         * Gets the flags of the item.
-         */
-        public @Flags int getFlags() {
-            return mFlags;
-        }
-
-        /**
-         * Returns whether this item is browsable.
-         * @see #FLAG_BROWSABLE
-         */
-        public boolean isBrowsable() {
-            return (mFlags & FLAG_BROWSABLE) != 0;
-        }
-
-        /**
-         * Returns whether this item is playable.
-         * @see #FLAG_PLAYABLE
-         */
-        public boolean isPlayable() {
-            return (mFlags & FLAG_PLAYABLE) != 0;
-        }
-
-        /**
-         * Returns the description of the media.
-         */
-        public @NonNull MediaDescription getDescription() {
-            return mDescription;
-        }
-
-        /**
-         * Returns the media id in the {@link MediaDescription} for this item.
-         * @see android.media.MediaMetadata#METADATA_KEY_MEDIA_ID
-         */
-        public @Nullable String getMediaId() {
-            return mDescription.getMediaId();
-        }
-    }
-
-    /**
-     * Callbacks for connection related events.
-     */
-    public static class ConnectionCallback {
-        /**
-         * Invoked after {@link MediaBrowser#connect()} when the request has successfully completed.
-         */
-        public void onConnected() {
-        }
-
-        /**
-         * Invoked when the client is disconnected from the media browser.
-         */
-        public void onConnectionSuspended() {
-        }
-
-        /**
-         * Invoked when the connection to the media browser failed.
-         */
-        public void onConnectionFailed() {
-        }
-    }
-
-    /**
-     * Callbacks for subscription related events.
-     */
-    public static abstract class SubscriptionCallback {
-        Binder mToken;
-
-        public SubscriptionCallback() {
-            mToken = new Binder();
-        }
-
-        /**
-         * Called when the list of children is loaded or updated.
-         *
-         * @param parentId The media id of the parent media item.
-         * @param children The children which were loaded.
-         */
-        public void onChildrenLoaded(@NonNull String parentId, @NonNull List<MediaItem> children) {
-        }
-
-        /**
-         * Called when the list of children is loaded or updated.
-         *
-         * @param parentId The media id of the parent media item.
-         * @param children The children which were loaded.
-         * @param options The bundle of service-specific arguments sent to the media
-         *            browser service. The contents of this bundle may affect the
-         *            information returned when browsing.
-         */
-        public void onChildrenLoaded(@NonNull String parentId, @NonNull List<MediaItem> children,
-                @NonNull Bundle options) {
-        }
-
-        /**
-         * Called when the id doesn't exist or other errors in subscribing.
-         * <p>
-         * If this is called, the subscription remains until {@link MediaBrowser#unsubscribe}
-         * called, because some errors may heal themselves.
-         * </p>
-         *
-         * @param parentId The media id of the parent media item whose children could
-         *            not be loaded.
-         */
-        public void onError(@NonNull String parentId) {
-        }
-
-        /**
-         * Called when the id doesn't exist or other errors in subscribing.
-         * <p>
-         * If this is called, the subscription remains until {@link MediaBrowser#unsubscribe}
-         * called, because some errors may heal themselves.
-         * </p>
-         *
-         * @param parentId The media id of the parent media item whose children could
-         *            not be loaded.
-         * @param options The bundle of service-specific arguments sent to the media
-         *            browser service.
-         */
-        public void onError(@NonNull String parentId, @NonNull Bundle options) {
-        }
-    }
-
-    /**
-     * Callback for receiving the result of {@link #getItem}.
-     */
-    public static abstract class ItemCallback {
-        /**
-         * Called when the item has been returned by the connected service.
-         *
-         * @param item The item that was returned or null if it doesn't exist.
-         */
-        public void onItemLoaded(MediaItem item) {
-        }
-
-        /**
-         * Called there was an error retrieving it or the connected service doesn't support
-         * {@link #getItem}.
-         *
-         * @param mediaId The media id of the media item which could not be loaded.
-         */
-        public void onError(@NonNull String mediaId) {
-        }
-    }
-
-    /**
-     * ServiceConnection to the other app.
-     */
-    private class MediaServiceConnection implements ServiceConnection {
-        @Override
-        public void onServiceConnected(final ComponentName name, final IBinder binder) {
-            postOrRun(new Runnable() {
-                @Override
-                public void run() {
-                    if (DBG) {
-                        Log.d(TAG, "MediaServiceConnection.onServiceConnected name=" + name
-                                + " binder=" + binder);
-                        dump();
-                    }
-
-                    // Make sure we are still the current connection, and that they haven't called
-                    // disconnect().
-                    if (!isCurrent("onServiceConnected")) {
-                        return;
-                    }
-
-                    // Save their binder
-                    mServiceBinder = IMediaBrowserService.Stub.asInterface(binder);
-
-                    // We make a new mServiceCallbacks each time we connect so that we can drop
-                    // responses from previous connections.
-                    mServiceCallbacks = getNewServiceCallbacks();
-                    mState = CONNECT_STATE_CONNECTING;
-
-                    // Call connect, which is async. When we get a response from that we will
-                    // say that we're connected.
-                    try {
-                        if (DBG) {
-                            Log.d(TAG, "ServiceCallbacks.onConnect...");
-                            dump();
-                        }
-                        mServiceBinder.connect(mContext.getPackageName(), mRootHints,
-                                mServiceCallbacks);
-                    } catch (RemoteException ex) {
-                        // Connect failed, which isn't good. But the auto-reconnect on the service
-                        // will take over and we will come back. We will also get the
-                        // onServiceDisconnected, which has all the cleanup code. So let that do
-                        // it.
-                        Log.w(TAG, "RemoteException during connect for " + mServiceComponent);
-                        if (DBG) {
-                            Log.d(TAG, "ServiceCallbacks.onConnect...");
-                            dump();
-                        }
-                    }
-                }
-            });
-        }
-
-        @Override
-        public void onServiceDisconnected(final ComponentName name) {
-            postOrRun(new Runnable() {
-                @Override
-                public void run() {
-                    if (DBG) {
-                        Log.d(TAG, "MediaServiceConnection.onServiceDisconnected name=" + name
-                                + " this=" + this + " mServiceConnection=" + mServiceConnection);
-                        dump();
-                    }
-
-                    // Make sure we are still the current connection, and that they haven't called
-                    // disconnect().
-                    if (!isCurrent("onServiceDisconnected")) {
-                        return;
-                    }
-
-                    // Clear out what we set in onServiceConnected
-                    mServiceBinder = null;
-                    mServiceCallbacks = null;
-
-                    // And tell the app that it's suspended.
-                    mState = CONNECT_STATE_SUSPENDED;
-                    mCallback.onConnectionSuspended();
-                }
-            });
-        }
-
-        private void postOrRun(Runnable r) {
-            if (Thread.currentThread() == mHandler.getLooper().getThread()) {
-                r.run();
-            } else {
-                mHandler.post(r);
-            }
-        }
-
-        /**
-         * Return true if this is the current ServiceConnection. Also logs if it's not.
-         */
-        private boolean isCurrent(String funcName) {
-            if (mServiceConnection != this || mState == CONNECT_STATE_DISCONNECTING
-                    || mState == CONNECT_STATE_DISCONNECTED) {
-                if (mState != CONNECT_STATE_DISCONNECTING && mState != CONNECT_STATE_DISCONNECTED) {
-                    // Check mState, because otherwise this log is noisy.
-                    Log.i(TAG, funcName + " for " + mServiceComponent + " with mServiceConnection="
-                            + mServiceConnection + " this=" + this);
-                }
-                return false;
-            }
-            return true;
-        }
-    }
-
-    /**
-     * Callbacks from the service.
-     */
-    private static class ServiceCallbacks extends IMediaBrowserServiceCallbacks.Stub {
-        private WeakReference<MediaBrowser> mMediaBrowser;
-
-        public ServiceCallbacks(MediaBrowser mediaBrowser) {
-            mMediaBrowser = new WeakReference<MediaBrowser>(mediaBrowser);
-        }
-
-        /**
-         * The other side has acknowledged our connection. The parameters to this function
-         * are the initial data as requested.
-         */
-        @Override
-        public void onConnect(String root, MediaSession.Token session,
-                final Bundle extras) {
-            MediaBrowser mediaBrowser = mMediaBrowser.get();
-            if (mediaBrowser != null) {
-                mediaBrowser.onServiceConnected(this, root, session, extras);
-            }
-        }
-
-        /**
-         * The other side does not like us. Tell the app via onConnectionFailed.
-         */
-        @Override
-        public void onConnectFailed() {
-            MediaBrowser mediaBrowser = mMediaBrowser.get();
-            if (mediaBrowser != null) {
-                mediaBrowser.onConnectionFailed(this);
-            }
-        }
-
-        @Override
-        public void onLoadChildren(String parentId, MediaParceledListSlice list) {
-            onLoadChildrenWithOptions(parentId, list, null);
-        }
-
-        @Override
-        public void onLoadChildrenWithOptions(String parentId, MediaParceledListSlice list,
-                final Bundle options) {
-            MediaBrowser mediaBrowser = mMediaBrowser.get();
-            if (mediaBrowser != null) {
-                mediaBrowser.onLoadChildren(this, parentId, list, options);
-            }
-        }
-    }
-
-    private static class Subscription {
-        private final List<SubscriptionCallback> mCallbacks;
-        private final List<Bundle> mOptionsList;
-
-        public Subscription() {
-            mCallbacks = new ArrayList<>();
-            mOptionsList = new ArrayList<>();
-        }
-
-        public boolean isEmpty() {
-            return mCallbacks.isEmpty();
-        }
-
-        public List<Bundle> getOptionsList() {
-            return mOptionsList;
-        }
-
-        public List<SubscriptionCallback> getCallbacks() {
-            return mCallbacks;
-        }
-
-        public SubscriptionCallback getCallback(Context context, Bundle options) {
-            if (options != null) {
-                options.setClassLoader(context.getClassLoader());
-            }
-            for (int i = 0; i < mOptionsList.size(); ++i) {
-                if (MediaBrowserUtils.areSameOptions(mOptionsList.get(i), options)) {
-                    return mCallbacks.get(i);
-                }
-            }
-            return null;
-        }
-
-        public void putCallback(Context context, Bundle options, SubscriptionCallback callback) {
-            if (options != null) {
-                options.setClassLoader(context.getClassLoader());
-            }
-            for (int i = 0; i < mOptionsList.size(); ++i) {
-                if (MediaBrowserUtils.areSameOptions(mOptionsList.get(i), options)) {
-                    mCallbacks.set(i, callback);
-                    return;
-                }
-            }
-            mCallbacks.add(callback);
-            mOptionsList.add(options);
-        }
-    }
-}
diff --git a/packages/MediaComponents/apex/java/android/media/browse/MediaBrowserUtils.java b/packages/MediaComponents/apex/java/android/media/browse/MediaBrowserUtils.java
deleted file mode 100644
index 2943e60..0000000
--- a/packages/MediaComponents/apex/java/android/media/browse/MediaBrowserUtils.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2016 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.browse;
-
-import android.os.Bundle;
-
-/**
- * @hide
- */
-public class MediaBrowserUtils {
-    public static boolean areSameOptions(Bundle options1, Bundle options2) {
-        if (options1 == options2) {
-            return true;
-        } else if (options1 == null) {
-            return options2.getInt(MediaBrowser.EXTRA_PAGE, -1) == -1
-                    && options2.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1) == -1;
-        } else if (options2 == null) {
-            return options1.getInt(MediaBrowser.EXTRA_PAGE, -1) == -1
-                    && options1.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1) == -1;
-        } else {
-            return options1.getInt(MediaBrowser.EXTRA_PAGE, -1)
-                    == options2.getInt(MediaBrowser.EXTRA_PAGE, -1)
-                    && options1.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1)
-                    == options2.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1);
-        }
-    }
-
-    public static boolean hasDuplicatedItems(Bundle options1, Bundle options2) {
-        int page1 = options1 == null ? -1 : options1.getInt(MediaBrowser.EXTRA_PAGE, -1);
-        int page2 = options2 == null ? -1 : options2.getInt(MediaBrowser.EXTRA_PAGE, -1);
-        int pageSize1 = options1 == null ? -1 : options1.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1);
-        int pageSize2 = options2 == null ? -1 : options2.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1);
-
-        int startIndex1, startIndex2, endIndex1, endIndex2;
-        if (page1 == -1 || pageSize1 == -1) {
-            startIndex1 = 0;
-            endIndex1 = Integer.MAX_VALUE;
-        } else {
-            startIndex1 = pageSize1 * page1;
-            endIndex1 = startIndex1 + pageSize1 - 1;
-        }
-
-        if (page2 == -1 || pageSize2 == -1) {
-            startIndex2 = 0;
-            endIndex2 = Integer.MAX_VALUE;
-        } else {
-            startIndex2 = pageSize2 * page2;
-            endIndex2 = startIndex2 + pageSize2 - 1;
-        }
-
-        if (startIndex1 <= startIndex2 && startIndex2 <= endIndex1) {
-            return true;
-        } else if (startIndex1 <= endIndex2 && endIndex2 <= endIndex1) {
-            return true;
-        }
-        return false;
-    }
-}
diff --git a/packages/MediaComponents/apex/java/android/media/session/IActiveSessionsListener.aidl b/packages/MediaComponents/apex/java/android/media/session/IActiveSessionsListener.aidl
deleted file mode 100644
index 4b9e4bd..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/IActiveSessionsListener.aidl
+++ /dev/null
@@ -1,26 +0,0 @@
-/* Copyright (C) 2014 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.session;
-
-import android.media.session.MediaSession;
-
-/**
- * Listens for changes to the list of active sessions.
- * @hide
- */
-oneway interface IActiveSessionsListener {
-    void onActiveSessionsChanged(in List<MediaSession.Token> sessions);
-}
diff --git a/packages/MediaComponents/apex/java/android/media/session/ICallback.aidl b/packages/MediaComponents/apex/java/android/media/session/ICallback.aidl
deleted file mode 100644
index 322bffa..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/ICallback.aidl
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Copyright (C) 2016 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.session;
-
-import android.app.PendingIntent;
-import android.content.ComponentName;
-import android.media.session.MediaSession;
-import android.view.KeyEvent;
-
-/**
- * @hide
- */
-oneway interface ICallback {
-    void onMediaKeyEventDispatchedToMediaSession(in KeyEvent event,
-            in MediaSession.Token sessionToken);
-    void onMediaKeyEventDispatchedToMediaButtonReceiver(in KeyEvent event,
-            in ComponentName mediaButtonReceiver);
-
-    void onAddressedPlayerChangedToMediaSession(in MediaSession.Token sessionToken);
-    void onAddressedPlayerChangedToMediaButtonReceiver(in ComponentName mediaButtonReceiver);
-}
-
diff --git a/packages/MediaComponents/apex/java/android/media/session/IOnMediaKeyListener.aidl b/packages/MediaComponents/apex/java/android/media/session/IOnMediaKeyListener.aidl
deleted file mode 100644
index aa98ea3..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/IOnMediaKeyListener.aidl
+++ /dev/null
@@ -1,28 +0,0 @@
-/* Copyright (C) 2016 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.session;
-
-import android.os.ResultReceiver;
-import android.view.KeyEvent;
-
-/**
- * Listener to handle media key.
- * @hide
- */
-oneway interface IOnMediaKeyListener {
-    void onMediaKey(in KeyEvent event, in ResultReceiver result);
-}
-
diff --git a/packages/MediaComponents/apex/java/android/media/session/IOnVolumeKeyLongPressListener.aidl b/packages/MediaComponents/apex/java/android/media/session/IOnVolumeKeyLongPressListener.aidl
deleted file mode 100644
index 07b8347..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/IOnVolumeKeyLongPressListener.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-/* Copyright (C) 2016 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.session;
-
-import android.view.KeyEvent;
-
-/**
- * Listener to handle volume key long-press.
- * @hide
- */
-oneway interface IOnVolumeKeyLongPressListener {
-    void onVolumeKeyLongPress(in KeyEvent event);
-}
-
diff --git a/packages/MediaComponents/apex/java/android/media/session/ISession.aidl b/packages/MediaComponents/apex/java/android/media/session/ISession.aidl
deleted file mode 100644
index 14b1c64..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/ISession.aidl
+++ /dev/null
@@ -1,54 +0,0 @@
-/* Copyright (C) 2014 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.session;
-
-import android.app.PendingIntent;
-//import android.media.AudioAttributes;
-import android.media.MediaMetadata;
-import android.media.MediaParceledListSlice;
-import android.media.session.ISessionController;
-import android.media.session.PlaybackState;
-import android.media.session.MediaSession;
-import android.os.Bundle;
-import android.os.ResultReceiver;
-
-/**
- * Interface to a MediaSession in the system.
- * @hide
- */
-interface ISession {
-    void sendEvent(String event, in Bundle data);
-    ISessionController getController();
-    void setFlags(int flags);
-    void setActive(boolean active);
-    void setMediaButtonReceiver(in PendingIntent mbr);
-    void setLaunchPendingIntent(in PendingIntent pi);
-    void destroy();
-
-    // These commands are for the TransportPerformer
-    void setMetadata(in MediaMetadata metadata, long duration, String metadataDescription);
-    void setPlaybackState(in PlaybackState state);
-    void setQueue(in MediaParceledListSlice queue);
-    void setQueueTitle(CharSequence title);
-    void setExtras(in Bundle extras);
-    void setRatingType(int type);
-
-    // These commands relate to volume handling
-    //TODO(b/119751592): Decide if AudioAttributes should be updated.
-    //void setPlaybackToLocal(in AudioAttributes attributes);
-    void setPlaybackToRemote(int control, int max);
-    void setCurrentVolume(int currentVolume);
-}
diff --git a/packages/MediaComponents/apex/java/android/media/session/ISessionCallback.aidl b/packages/MediaComponents/apex/java/android/media/session/ISessionCallback.aidl
deleted file mode 100644
index 626338d..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/ISessionCallback.aidl
+++ /dev/null
@@ -1,71 +0,0 @@
-/* Copyright (C) 2014 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.session;
-
-import android.content.Intent;
-import android.media.Rating;
-import android.media.session.ISessionControllerCallback;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.ResultReceiver;
-
-/**
- * @hide
- */
-oneway interface ISessionCallback {
-    void onCommand(String packageName, int pid, int uid, ISessionControllerCallback caller,
-            String command, in Bundle args, in ResultReceiver cb);
-    void onMediaButton(String packageName, int pid, int uid, in Intent mediaButtonIntent,
-            int sequenceNumber, in ResultReceiver cb);
-    void onMediaButtonFromController(String packageName, int pid, int uid,
-            ISessionControllerCallback caller, in Intent mediaButtonIntent);
-
-    // These callbacks are for the TransportPerformer
-    void onPrepare(String packageName, int pid, int uid, ISessionControllerCallback caller);
-    void onPrepareFromMediaId(String packageName, int pid, int uid,
-            ISessionControllerCallback caller, String mediaId, in Bundle extras);
-    void onPrepareFromSearch(String packageName, int pid, int uid,
-            ISessionControllerCallback caller, String query, in Bundle extras);
-    void onPrepareFromUri(String packageName, int pid, int uid, ISessionControllerCallback caller,
-            in Uri uri, in Bundle extras);
-    void onPlay(String packageName, int pid, int uid, ISessionControllerCallback caller);
-    void onPlayFromMediaId(String packageName, int pid, int uid, ISessionControllerCallback caller,
-            String mediaId, in Bundle extras);
-    void onPlayFromSearch(String packageName, int pid, int uid, ISessionControllerCallback caller,
-            String query, in Bundle extras);
-    void onPlayFromUri(String packageName, int pid, int uid, ISessionControllerCallback caller,
-            in Uri uri, in Bundle extras);
-    void onSkipToTrack(String packageName, int pid, int uid, ISessionControllerCallback caller,
-            long id);
-    void onPause(String packageName, int pid, int uid, ISessionControllerCallback caller);
-    void onStop(String packageName, int pid, int uid, ISessionControllerCallback caller);
-    void onNext(String packageName, int pid, int uid, ISessionControllerCallback caller);
-    void onPrevious(String packageName, int pid, int uid, ISessionControllerCallback caller);
-    void onFastForward(String packageName, int pid, int uid, ISessionControllerCallback caller);
-    void onRewind(String packageName, int pid, int uid, ISessionControllerCallback caller);
-    void onSeekTo(String packageName, int pid, int uid, ISessionControllerCallback caller,
-            long pos);
-    void onRate(String packageName, int pid, int uid, ISessionControllerCallback caller,
-            in Rating rating);
-    void onCustomAction(String packageName, int pid, int uid, ISessionControllerCallback caller,
-            String action, in Bundle args);
-
-    // These callbacks are for volume handling
-    void onAdjustVolume(String packageName, int pid, int uid, ISessionControllerCallback caller,
-            int direction);
-    void onSetVolumeTo(String packageName, int pid, int uid,
-            ISessionControllerCallback caller, int value);
-}
diff --git a/packages/MediaComponents/apex/java/android/media/session/ISessionController.aidl b/packages/MediaComponents/apex/java/android/media/session/ISessionController.aidl
deleted file mode 100644
index 433b12f..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/ISessionController.aidl
+++ /dev/null
@@ -1,88 +0,0 @@
-/* Copyright (C) 2014 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.session;
-
-import android.app.PendingIntent;
-import android.content.Intent;
-import android.media.MediaMetadata;
-import android.media.MediaParceledListSlice;
-import android.media.Rating;
-import android.media.session.ISessionControllerCallback;
-import android.media.session.MediaSession;
-import android.media.session.ParcelableVolumeInfo;
-import android.media.session.PlaybackState;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.ResultReceiver;
-import android.view.KeyEvent;
-
-import java.util.List;
-
-/**
- * Interface to MediaSessionRecord in the system.
- * @hide
- */
-interface ISessionController {
-    void sendCommand(String packageName, ISessionControllerCallback caller,
-            String command, in Bundle args, in ResultReceiver cb);
-    boolean sendMediaButton(String packageName, ISessionControllerCallback caller,
-            boolean asSystemService, in KeyEvent mediaButton);
-    void registerCallbackListener(String packageName, ISessionControllerCallback cb);
-    void unregisterCallbackListener(ISessionControllerCallback cb);
-    boolean isTransportControlEnabled();
-    String getPackageName();
-    String getTag();
-    PendingIntent getLaunchPendingIntent();
-    long getFlags();
-    ParcelableVolumeInfo getVolumeAttributes();
-    void adjustVolume(String packageName, String opPackageName, ISessionControllerCallback caller,
-            boolean asSystemService, int direction, int flags);
-    void setVolumeTo(String packageName, String opPackageName, ISessionControllerCallback caller,
-            int value, int flags);
-
-    // These commands are for the TransportControls
-    void prepare(String packageName, ISessionControllerCallback caller);
-    void prepareFromMediaId(String packageName, ISessionControllerCallback caller,
-            String mediaId, in Bundle extras);
-    void prepareFromSearch(String packageName, ISessionControllerCallback caller,
-            String string, in Bundle extras);
-    void prepareFromUri(String packageName, ISessionControllerCallback caller,
-            in Uri uri, in Bundle extras);
-    void play(String packageName, ISessionControllerCallback caller);
-    void playFromMediaId(String packageName, ISessionControllerCallback caller,
-            String mediaId, in Bundle extras);
-    void playFromSearch(String packageName, ISessionControllerCallback caller,
-            String string, in Bundle extras);
-    void playFromUri(String packageName, ISessionControllerCallback caller,
-            in Uri uri, in Bundle extras);
-    void skipToQueueItem(String packageName, ISessionControllerCallback caller, long id);
-    void pause(String packageName, ISessionControllerCallback caller);
-    void stop(String packageName, ISessionControllerCallback caller);
-    void next(String packageName, ISessionControllerCallback caller);
-    void previous(String packageName, ISessionControllerCallback caller);
-    void fastForward(String packageName, ISessionControllerCallback caller);
-    void rewind(String packageName, ISessionControllerCallback caller);
-    void seekTo(String packageName, ISessionControllerCallback caller, long pos);
-    void rate(String packageName, ISessionControllerCallback caller, in Rating rating);
-    void sendCustomAction(String packageName, ISessionControllerCallback caller,
-            String action, in Bundle args);
-    MediaMetadata getMetadata();
-    PlaybackState getPlaybackState();
-    MediaParceledListSlice getQueue();
-    CharSequence getQueueTitle();
-    Bundle getExtras();
-    int getRatingType();
-}
diff --git a/packages/MediaComponents/apex/java/android/media/session/ISessionControllerCallback.aidl b/packages/MediaComponents/apex/java/android/media/session/ISessionControllerCallback.aidl
deleted file mode 100644
index f5cc4f6..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/ISessionControllerCallback.aidl
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Copyright (C) 2014 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.session;
-
-import android.media.MediaMetadata;
-import android.media.MediaParceledListSlice;
-import android.media.session.ParcelableVolumeInfo;
-import android.media.session.PlaybackState;
-import android.media.session.MediaSession;
-import android.os.Bundle;
-
-/**
- * @hide
- */
-oneway interface ISessionControllerCallback {
-    void onEvent(String event, in Bundle extras);
-    void onSessionDestroyed();
-
-    // These callbacks are for the TransportController
-    void onPlaybackStateChanged(in PlaybackState state);
-    void onMetadataChanged(in MediaMetadata metadata);
-    void onQueueChanged(in MediaParceledListSlice queue);
-    void onQueueTitleChanged(CharSequence title);
-    void onExtrasChanged(in Bundle extras);
-    void onVolumeInfoChanged(in ParcelableVolumeInfo info);
-}
diff --git a/packages/MediaComponents/apex/java/android/media/session/ISessionManager.aidl b/packages/MediaComponents/apex/java/android/media/session/ISessionManager.aidl
deleted file mode 100644
index d6c226f..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/ISessionManager.aidl
+++ /dev/null
@@ -1,58 +0,0 @@
-/* Copyright (C) 2014 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.session;
-
-import android.content.ComponentName;
-import android.media.IRemoteVolumeController;
-import android.media.session.IActiveSessionsListener;
-import android.media.session.ICallback;
-import android.media.session.IOnMediaKeyListener;
-import android.media.session.IOnVolumeKeyLongPressListener;
-import android.media.session.ISession;
-import android.media.session.ISessionCallback;
-import android.os.Bundle;
-import android.view.KeyEvent;
-
-/**
- * Interface to the MediaSessionManagerService
- * @hide
- */
-interface ISessionManager {
-    ISession createSession(String packageName, in ISessionCallback cb, String tag, int userId);
-    List<IBinder> getSessions(in ComponentName compName, int userId);
-    void dispatchMediaKeyEvent(String packageName, boolean asSystemService, in KeyEvent keyEvent,
-            boolean needWakeLock);
-    void dispatchVolumeKeyEvent(String packageName, String opPackageName, boolean asSystemService,
-            in KeyEvent keyEvent, int stream, boolean musicOnly);
-    void dispatchAdjustVolume(String packageName, String opPackageName, int suggestedStream,
-            int delta, int flags);
-    void addSessionsListener(in IActiveSessionsListener listener, in ComponentName compName,
-            int userId);
-    void removeSessionsListener(in IActiveSessionsListener listener);
-
-    // This is for the system volume UI only
-    void setRemoteVolumeController(in IRemoteVolumeController rvc);
-
-    // For PhoneWindowManager to precheck media keys
-    boolean isGlobalPriorityActive();
-
-    void setCallback(in ICallback callback);
-    void setOnVolumeKeyLongPressListener(in IOnVolumeKeyLongPressListener listener);
-    void setOnMediaKeyListener(in IOnMediaKeyListener listener);
-
-    // MediaSession2
-    boolean isTrusted(String controllerPackageName, int controllerPid, int controllerUid);
-}
diff --git a/packages/MediaComponents/apex/java/android/media/session/MediaController.java b/packages/MediaComponents/apex/java/android/media/session/MediaController.java
deleted file mode 100644
index 65682a8..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/MediaController.java
+++ /dev/null
@@ -1,1190 +0,0 @@
-/*
- * Copyright (C) 2014 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.session;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.media.AudioAttributes;
-import android.media.AudioManager;
-import android.media.MediaMetadata;
-import android.media.MediaParceledListSlice;
-import android.media.Rating;
-import android.media.VolumeProvider;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.KeyEvent;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Allows an app to interact with an ongoing media session. Media buttons and
- * other commands can be sent to the session. A callback may be registered to
- * receive updates from the session, such as metadata and play state changes.
- * <p>
- * A MediaController can be created through {@link MediaSessionManager} if you
- * hold the "android.permission.MEDIA_CONTENT_CONTROL" permission or are an
- * enabled notification listener or by getting a {@link MediaSession.Token}
- * directly from the session owner.
- * <p>
- * MediaController objects are thread-safe.
- */
-public final class MediaController {
-    private static final String TAG = "MediaController";
-
-    private static final int MSG_EVENT = 1;
-    private static final int MSG_UPDATE_PLAYBACK_STATE = 2;
-    private static final int MSG_UPDATE_METADATA = 3;
-    private static final int MSG_UPDATE_VOLUME = 4;
-    private static final int MSG_UPDATE_QUEUE = 5;
-    private static final int MSG_UPDATE_QUEUE_TITLE = 6;
-    private static final int MSG_UPDATE_EXTRAS = 7;
-    private static final int MSG_DESTROYED = 8;
-
-    private final ISessionController mSessionBinder;
-
-    private final MediaSession.Token mToken;
-    private final Context mContext;
-    private final CallbackStub mCbStub = new CallbackStub(this);
-    private final ArrayList<MessageHandler> mCallbacks = new ArrayList<MessageHandler>();
-    private final Object mLock = new Object();
-
-    private boolean mCbRegistered = false;
-    private String mPackageName;
-    private String mTag;
-
-    private final TransportControls mTransportControls;
-
-    /**
-     * Call for creating a MediaController directly from a binder. Should only
-     * be used by framework code.
-     *
-     * @hide
-     */
-    public MediaController(Context context, ISessionController sessionBinder) {
-        if (sessionBinder == null) {
-            throw new IllegalArgumentException("Session token cannot be null");
-        }
-        if (context == null) {
-            throw new IllegalArgumentException("Context cannot be null");
-        }
-        mSessionBinder = sessionBinder;
-        mTransportControls = new TransportControls();
-        mToken = new MediaSession.Token(sessionBinder);
-        mContext = context;
-    }
-
-    /**
-     * Create a new MediaController from a session's token.
-     *
-     * @param context The caller's context.
-     * @param token The token for the session.
-     */
-    public MediaController(@NonNull Context context, @NonNull MediaSession.Token token) {
-        this(context, token.getBinder());
-    }
-
-    /**
-     * Get a {@link TransportControls} instance to send transport actions to
-     * the associated session.
-     *
-     * @return A transport controls instance.
-     */
-    public @NonNull TransportControls getTransportControls() {
-        return mTransportControls;
-    }
-
-    /**
-     * Send the specified media button event to the session. Only media keys can
-     * be sent by this method, other keys will be ignored.
-     *
-     * @param keyEvent The media button event to dispatch.
-     * @return true if the event was sent to the session, false otherwise.
-     */
-    public boolean dispatchMediaButtonEvent(@NonNull KeyEvent keyEvent) {
-        return dispatchMediaButtonEventInternal(false, keyEvent);
-    }
-
-    /**
-     * Dispatches the media button event as system service to the session.
-     * <p>
-     * Should be only called by the {@link com.android.internal.policy.PhoneWindow} when the
-     * foreground activity didn't consume the key from the hardware devices.
-     *
-     * @param keyEvent media key event
-     * @return {@code true} if the event was sent to the session, {@code false} otherwise
-     * @hide
-     */
-    public boolean dispatchMediaButtonEventAsSystemService(@NonNull KeyEvent keyEvent) {
-        return dispatchMediaButtonEventInternal(true, keyEvent);
-    }
-
-    private boolean dispatchMediaButtonEventInternal(boolean asSystemService,
-            @NonNull KeyEvent keyEvent) {
-        if (keyEvent == null) {
-            throw new IllegalArgumentException("KeyEvent may not be null");
-        }
-        if (!KeyEvent.isMediaSessionKey(keyEvent.getKeyCode())) {
-            return false;
-        }
-        try {
-            return mSessionBinder.sendMediaButton(mContext.getPackageName(), mCbStub,
-                    asSystemService, keyEvent);
-        } catch (RemoteException e) {
-            // System is dead. =(
-        }
-        return false;
-    }
-
-    /**
-     * Dispatches the volume button event as system service to the session.
-     * <p>
-     * Should be only called by the {@link com.android.internal.policy.PhoneWindow} when the
-     * foreground activity didn't consume the key from the hardware devices.
-     *
-     * @param keyEvent volume key event
-     * @hide
-     */
-    public void dispatchVolumeButtonEventAsSystemService(@NonNull KeyEvent keyEvent) {
-        switch (keyEvent.getAction()) {
-            case KeyEvent.ACTION_DOWN: {
-                int direction = 0;
-                switch (keyEvent.getKeyCode()) {
-                    case KeyEvent.KEYCODE_VOLUME_UP:
-                        direction = AudioManager.ADJUST_RAISE;
-                        break;
-                    case KeyEvent.KEYCODE_VOLUME_DOWN:
-                        direction = AudioManager.ADJUST_LOWER;
-                        break;
-                    case KeyEvent.KEYCODE_VOLUME_MUTE:
-                        direction = AudioManager.ADJUST_TOGGLE_MUTE;
-                        break;
-                }
-                try {
-                    mSessionBinder.adjustVolume(mContext.getPackageName(),
-                            mContext.getOpPackageName(), mCbStub, true, direction,
-                            AudioManager.FLAG_SHOW_UI);
-                } catch (RemoteException e) {
-                    Log.wtf(TAG, "Error calling adjustVolumeBy", e);
-                }
-            }
-
-            case KeyEvent.ACTION_UP: {
-                final int flags = AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE
-                        | AudioManager.FLAG_FROM_KEY;
-                try {
-                    mSessionBinder.adjustVolume(mContext.getPackageName(),
-                            mContext.getOpPackageName(), mCbStub, true, 0, flags);
-                } catch (RemoteException e) {
-                    Log.wtf(TAG, "Error calling adjustVolumeBy", e);
-                }
-            }
-        }
-    }
-
-    /**
-     * Get the current playback state for this session.
-     *
-     * @return The current PlaybackState or null
-     */
-    public @Nullable PlaybackState getPlaybackState() {
-        try {
-            return mSessionBinder.getPlaybackState();
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling getPlaybackState.", e);
-            return null;
-        }
-    }
-
-    /**
-     * Get the current metadata for this session.
-     *
-     * @return The current MediaMetadata or null.
-     */
-    public @Nullable MediaMetadata getMetadata() {
-        try {
-            return mSessionBinder.getMetadata();
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling getMetadata.", e);
-            return null;
-        }
-    }
-
-    /**
-     * Get the current play queue for this session if one is set. If you only
-     * care about the current item {@link #getMetadata()} should be used.
-     *
-     * @return The current play queue or null.
-     */
-    public @Nullable List<MediaSession.QueueItem> getQueue() {
-        try {
-            MediaParceledListSlice queue = mSessionBinder.getQueue();
-            if (queue != null) {
-                return queue.getList();
-            }
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling getQueue.", e);
-        }
-        return null;
-    }
-
-    /**
-     * Get the queue title for this session.
-     */
-    public @Nullable CharSequence getQueueTitle() {
-        try {
-            return mSessionBinder.getQueueTitle();
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling getQueueTitle", e);
-        }
-        return null;
-    }
-
-    /**
-     * Get the extras for this session.
-     */
-    public @Nullable Bundle getExtras() {
-        try {
-            return mSessionBinder.getExtras();
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling getExtras", e);
-        }
-        return null;
-    }
-
-    /**
-     * Get the rating type supported by the session. One of:
-     * <ul>
-     * <li>{@link Rating#RATING_NONE}</li>
-     * <li>{@link Rating#RATING_HEART}</li>
-     * <li>{@link Rating#RATING_THUMB_UP_DOWN}</li>
-     * <li>{@link Rating#RATING_3_STARS}</li>
-     * <li>{@link Rating#RATING_4_STARS}</li>
-     * <li>{@link Rating#RATING_5_STARS}</li>
-     * <li>{@link Rating#RATING_PERCENTAGE}</li>
-     * </ul>
-     *
-     * @return The supported rating type
-     */
-    public int getRatingType() {
-        try {
-            return mSessionBinder.getRatingType();
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling getRatingType.", e);
-            return Rating.RATING_NONE;
-        }
-    }
-
-    /**
-     * Get the flags for this session. Flags are defined in {@link MediaSession}.
-     *
-     * @return The current set of flags for the session.
-     */
-    public @MediaSession.SessionFlags long getFlags() {
-        try {
-            return mSessionBinder.getFlags();
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling getFlags.", e);
-        }
-        return 0;
-    }
-
-    /**
-     * Get the current playback info for this session.
-     *
-     * @return The current playback info or null.
-     */
-    public @Nullable PlaybackInfo getPlaybackInfo() {
-        try {
-            ParcelableVolumeInfo result = mSessionBinder.getVolumeAttributes();
-            return new PlaybackInfo(result.volumeType, result.audioAttrs, result.controlType,
-                    result.maxVolume, result.currentVolume);
-
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling getAudioInfo.", e);
-        }
-        return null;
-    }
-
-    /**
-     * Get an intent for launching UI associated with this session if one
-     * exists.
-     *
-     * @return A {@link PendingIntent} to launch UI or null.
-     */
-    public @Nullable PendingIntent getSessionActivity() {
-        try {
-            return mSessionBinder.getLaunchPendingIntent();
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling getPendingIntent.", e);
-        }
-        return null;
-    }
-
-    /**
-     * Get the token for the session this is connected to.
-     *
-     * @return The token for the connected session.
-     */
-    public @NonNull MediaSession.Token getSessionToken() {
-        return mToken;
-    }
-
-    /**
-     * Set the volume of the output this session is playing on. The command will
-     * be ignored if it does not support
-     * {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}. The flags in
-     * {@link AudioManager} may be used to affect the handling.
-     *
-     * @see #getPlaybackInfo()
-     * @param value The value to set it to, between 0 and the reported max.
-     * @param flags Flags from {@link AudioManager} to include with the volume
-     *            request.
-     */
-    public void setVolumeTo(int value, int flags) {
-        try {
-            mSessionBinder.setVolumeTo(mContext.getPackageName(), mContext.getOpPackageName(),
-                    mCbStub, value, flags);
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling setVolumeTo.", e);
-        }
-    }
-
-    /**
-     * Adjust the volume of the output this session is playing on. The direction
-     * must be one of {@link AudioManager#ADJUST_LOWER},
-     * {@link AudioManager#ADJUST_RAISE}, or {@link AudioManager#ADJUST_SAME}.
-     * The command will be ignored if the session does not support
-     * {@link VolumeProvider#VOLUME_CONTROL_RELATIVE} or
-     * {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}. The flags in
-     * {@link AudioManager} may be used to affect the handling.
-     *
-     * @see #getPlaybackInfo()
-     * @param direction The direction to adjust the volume in.
-     * @param flags Any flags to pass with the command.
-     */
-    public void adjustVolume(int direction, int flags) {
-        try {
-            mSessionBinder.adjustVolume(mContext.getPackageName(), mContext.getOpPackageName(),
-                    mCbStub, false, direction, flags);
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling adjustVolumeBy.", e);
-        }
-    }
-
-    /**
-     * Registers a callback to receive updates from the Session. Updates will be
-     * posted on the caller's thread.
-     *
-     * @param callback The callback object, must not be null.
-     */
-    public void registerCallback(@NonNull Callback callback) {
-        registerCallback(callback, null);
-    }
-
-    /**
-     * Registers a callback to receive updates from the session. Updates will be
-     * posted on the specified handler's thread.
-     *
-     * @param callback The callback object, must not be null.
-     * @param handler The handler to post updates on. If null the callers thread
-     *            will be used.
-     */
-    public void registerCallback(@NonNull Callback callback, @Nullable Handler handler) {
-        if (callback == null) {
-            throw new IllegalArgumentException("callback must not be null");
-        }
-        if (handler == null) {
-            handler = new Handler();
-        }
-        synchronized (mLock) {
-            addCallbackLocked(callback, handler);
-        }
-    }
-
-    /**
-     * Unregisters the specified callback. If an update has already been posted
-     * you may still receive it after calling this method.
-     *
-     * @param callback The callback to remove.
-     */
-    public void unregisterCallback(@NonNull Callback callback) {
-        if (callback == null) {
-            throw new IllegalArgumentException("callback must not be null");
-        }
-        synchronized (mLock) {
-            removeCallbackLocked(callback);
-        }
-    }
-
-    /**
-     * Sends a generic command to the session. It is up to the session creator
-     * to decide what commands and parameters they will support. As such,
-     * commands should only be sent to sessions that the controller owns.
-     *
-     * @param command The command to send
-     * @param args Any parameters to include with the command
-     * @param cb The callback to receive the result on
-     */
-    public void sendCommand(@NonNull String command, @Nullable Bundle args,
-            @Nullable ResultReceiver cb) {
-        if (TextUtils.isEmpty(command)) {
-            throw new IllegalArgumentException("command cannot be null or empty");
-        }
-        try {
-            mSessionBinder.sendCommand(mContext.getPackageName(), mCbStub, command, args, cb);
-        } catch (RemoteException e) {
-            Log.d(TAG, "Dead object in sendCommand.", e);
-        }
-    }
-
-    /**
-     * Get the session owner's package name.
-     *
-     * @return The package name of of the session owner.
-     */
-    public String getPackageName() {
-        if (mPackageName == null) {
-            try {
-                mPackageName = mSessionBinder.getPackageName();
-            } catch (RemoteException e) {
-                Log.d(TAG, "Dead object in getPackageName.", e);
-            }
-        }
-        return mPackageName;
-    }
-
-    /**
-     * Get the session's tag for debugging purposes.
-     *
-     * @return The session's tag.
-     * @hide
-     */
-    public String getTag() {
-        if (mTag == null) {
-            try {
-                mTag = mSessionBinder.getTag();
-            } catch (RemoteException e) {
-                Log.d(TAG, "Dead object in getTag.", e);
-            }
-        }
-        return mTag;
-    }
-
-    /*
-     * @hide
-     */
-    ISessionController getSessionBinder() {
-        return mSessionBinder;
-    }
-
-    /**
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public boolean controlsSameSession(MediaController other) {
-        if (other == null) return false;
-        return mSessionBinder.asBinder() == other.getSessionBinder().asBinder();
-    }
-
-    private void addCallbackLocked(Callback cb, Handler handler) {
-        if (getHandlerForCallbackLocked(cb) != null) {
-            Log.w(TAG, "Callback is already added, ignoring");
-            return;
-        }
-        MessageHandler holder = new MessageHandler(handler.getLooper(), cb);
-        mCallbacks.add(holder);
-        holder.mRegistered = true;
-
-        if (!mCbRegistered) {
-            try {
-                mSessionBinder.registerCallbackListener(mContext.getPackageName(), mCbStub);
-                mCbRegistered = true;
-            } catch (RemoteException e) {
-                Log.e(TAG, "Dead object in registerCallback", e);
-            }
-        }
-    }
-
-    private boolean removeCallbackLocked(Callback cb) {
-        boolean success = false;
-        for (int i = mCallbacks.size() - 1; i >= 0; i--) {
-            MessageHandler handler = mCallbacks.get(i);
-            if (cb == handler.mCallback) {
-                mCallbacks.remove(i);
-                success = true;
-                handler.mRegistered = false;
-            }
-        }
-        if (mCbRegistered && mCallbacks.size() == 0) {
-            try {
-                mSessionBinder.unregisterCallbackListener(mCbStub);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Dead object in removeCallbackLocked");
-            }
-            mCbRegistered = false;
-        }
-        return success;
-    }
-
-    private MessageHandler getHandlerForCallbackLocked(Callback cb) {
-        if (cb == null) {
-            throw new IllegalArgumentException("Callback cannot be null");
-        }
-        for (int i = mCallbacks.size() - 1; i >= 0; i--) {
-            MessageHandler handler = mCallbacks.get(i);
-            if (cb == handler.mCallback) {
-                return handler;
-            }
-        }
-        return null;
-    }
-
-    private final void postMessage(int what, Object obj, Bundle data) {
-        synchronized (mLock) {
-            for (int i = mCallbacks.size() - 1; i >= 0; i--) {
-                mCallbacks.get(i).post(what, obj, data);
-            }
-        }
-    }
-
-    /**
-     * Callback for receiving updates from the session. A Callback can be
-     * registered using {@link #registerCallback}.
-     */
-    public static abstract class Callback {
-        /**
-         * Override to handle the session being destroyed. The session is no
-         * longer valid after this call and calls to it will be ignored.
-         */
-        public void onSessionDestroyed() {
-        }
-
-        /**
-         * Override to handle custom events sent by the session owner without a
-         * specified interface. Controllers should only handle these for
-         * sessions they own.
-         *
-         * @param event The event from the session.
-         * @param extras Optional parameters for the event, may be null.
-         */
-        public void onSessionEvent(@NonNull String event, @Nullable Bundle extras) {
-        }
-
-        /**
-         * Override to handle changes in playback state.
-         *
-         * @param state The new playback state of the session
-         */
-        public void onPlaybackStateChanged(@Nullable PlaybackState state) {
-        }
-
-        /**
-         * Override to handle changes to the current metadata.
-         *
-         * @param metadata The current metadata for the session or null if none.
-         * @see MediaMetadata
-         */
-        public void onMetadataChanged(@Nullable MediaMetadata metadata) {
-        }
-
-        /**
-         * Override to handle changes to items in the queue.
-         *
-         * @param queue A list of items in the current play queue. It should
-         *            include the currently playing item as well as previous and
-         *            upcoming items if applicable.
-         * @see MediaSession.QueueItem
-         */
-        public void onQueueChanged(@Nullable List<MediaSession.QueueItem> queue) {
-        }
-
-        /**
-         * Override to handle changes to the queue title.
-         *
-         * @param title The title that should be displayed along with the play queue such as
-         *              "Now Playing". May be null if there is no such title.
-         */
-        public void onQueueTitleChanged(@Nullable CharSequence title) {
-        }
-
-        /**
-         * Override to handle changes to the {@link MediaSession} extras.
-         *
-         * @param extras The extras that can include other information associated with the
-         *               {@link MediaSession}.
-         */
-        public void onExtrasChanged(@Nullable Bundle extras) {
-        }
-
-        /**
-         * Override to handle changes to the audio info.
-         *
-         * @param info The current audio info for this session.
-         */
-        public void onAudioInfoChanged(PlaybackInfo info) {
-        }
-    }
-
-    /**
-     * Interface for controlling media playback on a session. This allows an app
-     * to send media transport commands to the session.
-     */
-    public final class TransportControls {
-        private static final String TAG = "TransportController";
-
-        private TransportControls() {
-        }
-
-        /**
-         * Request that the player prepare its playback. In other words, other sessions can continue
-         * to play during the preparation of this session. This method can be used to speed up the
-         * start of the playback. Once the preparation is done, the session will change its playback
-         * state to {@link PlaybackState#STATE_PAUSED}. Afterwards, {@link #play} can be called to
-         * start playback.
-         */
-        public void prepare() {
-            try {
-                mSessionBinder.prepare(mContext.getPackageName(), mCbStub);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling prepare.", e);
-            }
-        }
-
-        /**
-         * Request that the player prepare playback for a specific media id. In other words, other
-         * sessions can continue to play during the preparation of this session. This method can be
-         * used to speed up the start of the playback. Once the preparation is done, the session
-         * will change its playback state to {@link PlaybackState#STATE_PAUSED}. Afterwards,
-         * {@link #play} can be called to start playback. If the preparation is not needed,
-         * {@link #playFromMediaId} can be directly called without this method.
-         *
-         * @param mediaId The id of the requested media.
-         * @param extras Optional extras that can include extra information about the media item
-         *               to be prepared.
-         */
-        public void prepareFromMediaId(String mediaId, Bundle extras) {
-            if (TextUtils.isEmpty(mediaId)) {
-                throw new IllegalArgumentException(
-                        "You must specify a non-empty String for prepareFromMediaId.");
-            }
-            try {
-                mSessionBinder.prepareFromMediaId(mContext.getPackageName(), mCbStub, mediaId,
-                        extras);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling prepare(" + mediaId + ").", e);
-            }
-        }
-
-        /**
-         * Request that the player prepare playback for a specific search query. An empty or null
-         * query should be treated as a request to prepare any music. In other words, other sessions
-         * can continue to play during the preparation of this session. This method can be used to
-         * speed up the start of the playback. Once the preparation is done, the session will
-         * change its playback state to {@link PlaybackState#STATE_PAUSED}. Afterwards,
-         * {@link #play} can be called to start playback. If the preparation is not needed,
-         * {@link #playFromSearch} can be directly called without this method.
-         *
-         * @param query The search query.
-         * @param extras Optional extras that can include extra information
-         *               about the query.
-         */
-        public void prepareFromSearch(String query, Bundle extras) {
-            if (query == null) {
-                // This is to remain compatible with
-                // INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH
-                query = "";
-            }
-            try {
-                mSessionBinder.prepareFromSearch(mContext.getPackageName(), mCbStub, query,
-                        extras);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling prepare(" + query + ").", e);
-            }
-        }
-
-        /**
-         * Request that the player prepare playback for a specific {@link Uri}. In other words,
-         * other sessions can continue to play during the preparation of this session. This method
-         * can be used to speed up the start of the playback. Once the preparation is done, the
-         * session will change its playback state to {@link PlaybackState#STATE_PAUSED}. Afterwards,
-         * {@link #play} can be called to start playback. If the preparation is not needed,
-         * {@link #playFromUri} can be directly called without this method.
-         *
-         * @param uri The URI of the requested media.
-         * @param extras Optional extras that can include extra information about the media item
-         *               to be prepared.
-         */
-        public void prepareFromUri(Uri uri, Bundle extras) {
-            if (uri == null || Uri.EMPTY.equals(uri)) {
-                throw new IllegalArgumentException(
-                        "You must specify a non-empty Uri for prepareFromUri.");
-            }
-            try {
-                mSessionBinder.prepareFromUri(mContext.getPackageName(), mCbStub, uri, extras);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling prepare(" + uri + ").", e);
-            }
-        }
-
-        /**
-         * Request that the player start its playback at its current position.
-         */
-        public void play() {
-            try {
-                mSessionBinder.play(mContext.getPackageName(), mCbStub);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling play.", e);
-            }
-        }
-
-        /**
-         * Request that the player start playback for a specific media id.
-         *
-         * @param mediaId The id of the requested media.
-         * @param extras Optional extras that can include extra information about the media item
-         *               to be played.
-         */
-        public void playFromMediaId(String mediaId, Bundle extras) {
-            if (TextUtils.isEmpty(mediaId)) {
-                throw new IllegalArgumentException(
-                        "You must specify a non-empty String for playFromMediaId.");
-            }
-            try {
-                mSessionBinder.playFromMediaId(mContext.getPackageName(), mCbStub, mediaId,
-                        extras);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling play(" + mediaId + ").", e);
-            }
-        }
-
-        /**
-         * Request that the player start playback for a specific search query.
-         * An empty or null query should be treated as a request to play any
-         * music.
-         *
-         * @param query The search query.
-         * @param extras Optional extras that can include extra information
-         *               about the query.
-         */
-        public void playFromSearch(String query, Bundle extras) {
-            if (query == null) {
-                // This is to remain compatible with
-                // INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH
-                query = "";
-            }
-            try {
-                mSessionBinder.playFromSearch(mContext.getPackageName(), mCbStub, query, extras);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling play(" + query + ").", e);
-            }
-        }
-
-        /**
-         * Request that the player start playback for a specific {@link Uri}.
-         *
-         * @param uri The URI of the requested media.
-         * @param extras Optional extras that can include extra information about the media item
-         *               to be played.
-         */
-        public void playFromUri(Uri uri, Bundle extras) {
-            if (uri == null || Uri.EMPTY.equals(uri)) {
-                throw new IllegalArgumentException(
-                        "You must specify a non-empty Uri for playFromUri.");
-            }
-            try {
-                mSessionBinder.playFromUri(mContext.getPackageName(), mCbStub, uri, extras);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling play(" + uri + ").", e);
-            }
-        }
-
-        /**
-         * Play an item with a specific id in the play queue. If you specify an
-         * id that is not in the play queue, the behavior is undefined.
-         */
-        public void skipToQueueItem(long id) {
-            try {
-                mSessionBinder.skipToQueueItem(mContext.getPackageName(), mCbStub, id);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling skipToItem(" + id + ").", e);
-            }
-        }
-
-        /**
-         * Request that the player pause its playback and stay at its current
-         * position.
-         */
-        public void pause() {
-            try {
-                mSessionBinder.pause(mContext.getPackageName(), mCbStub);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling pause.", e);
-            }
-        }
-
-        /**
-         * Request that the player stop its playback; it may clear its state in
-         * whatever way is appropriate.
-         */
-        public void stop() {
-            try {
-                mSessionBinder.stop(mContext.getPackageName(), mCbStub);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling stop.", e);
-            }
-        }
-
-        /**
-         * Move to a new location in the media stream.
-         *
-         * @param pos Position to move to, in milliseconds.
-         */
-        public void seekTo(long pos) {
-            try {
-                mSessionBinder.seekTo(mContext.getPackageName(), mCbStub, pos);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling seekTo.", e);
-            }
-        }
-
-        /**
-         * Start fast forwarding. If playback is already fast forwarding this
-         * may increase the rate.
-         */
-        public void fastForward() {
-            try {
-                mSessionBinder.fastForward(mContext.getPackageName(), mCbStub);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling fastForward.", e);
-            }
-        }
-
-        /**
-         * Skip to the next item.
-         */
-        public void skipToNext() {
-            try {
-                mSessionBinder.next(mContext.getPackageName(), mCbStub);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling next.", e);
-            }
-        }
-
-        /**
-         * Start rewinding. If playback is already rewinding this may increase
-         * the rate.
-         */
-        public void rewind() {
-            try {
-                mSessionBinder.rewind(mContext.getPackageName(), mCbStub);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling rewind.", e);
-            }
-        }
-
-        /**
-         * Skip to the previous item.
-         */
-        public void skipToPrevious() {
-            try {
-                mSessionBinder.previous(mContext.getPackageName(), mCbStub);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling previous.", e);
-            }
-        }
-
-        /**
-         * Rate the current content. This will cause the rating to be set for
-         * the current user. The Rating type must match the type returned by
-         * {@link #getRatingType()}.
-         *
-         * @param rating The rating to set for the current content
-         */
-        public void setRating(Rating rating) {
-            try {
-                mSessionBinder.rate(mContext.getPackageName(), mCbStub, rating);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling rate.", e);
-            }
-        }
-
-        /**
-         * Send a custom action back for the {@link MediaSession} to perform.
-         *
-         * @param customAction The action to perform.
-         * @param args Optional arguments to supply to the {@link MediaSession} for this
-         *             custom action.
-         */
-        public void sendCustomAction(@NonNull PlaybackState.CustomAction customAction,
-                @Nullable Bundle args) {
-            if (customAction == null) {
-                throw new IllegalArgumentException("CustomAction cannot be null.");
-            }
-            sendCustomAction(customAction.getAction(), args);
-        }
-
-        /**
-         * Send the id and args from a custom action back for the {@link MediaSession} to perform.
-         *
-         * @see #sendCustomAction(PlaybackState.CustomAction action, Bundle args)
-         * @param action The action identifier of the {@link PlaybackState.CustomAction} as
-         *               specified by the {@link MediaSession}.
-         * @param args Optional arguments to supply to the {@link MediaSession} for this
-         *             custom action.
-         */
-        public void sendCustomAction(@NonNull String action, @Nullable Bundle args) {
-            if (TextUtils.isEmpty(action)) {
-                throw new IllegalArgumentException("CustomAction cannot be null.");
-            }
-            try {
-                mSessionBinder.sendCustomAction(mContext.getPackageName(), mCbStub, action, args);
-            } catch (RemoteException e) {
-                Log.d(TAG, "Dead object in sendCustomAction.", e);
-            }
-        }
-    }
-
-    /**
-     * Holds information about the current playback and how audio is handled for
-     * this session.
-     */
-    public static final class PlaybackInfo {
-        /**
-         * The session uses remote playback.
-         */
-        public static final int PLAYBACK_TYPE_REMOTE = 2;
-        /**
-         * The session uses local playback.
-         */
-        public static final int PLAYBACK_TYPE_LOCAL = 1;
-
-        private final int mVolumeType;
-        private final int mVolumeControl;
-        private final int mMaxVolume;
-        private final int mCurrentVolume;
-        private final AudioAttributes mAudioAttrs;
-
-        /**
-         * @hide
-         */
-        public PlaybackInfo(int type, AudioAttributes attrs, int control, int max, int current) {
-            mVolumeType = type;
-            mAudioAttrs = attrs;
-            mVolumeControl = control;
-            mMaxVolume = max;
-            mCurrentVolume = current;
-        }
-
-        /**
-         * Get the type of playback which affects volume handling. One of:
-         * <ul>
-         * <li>{@link #PLAYBACK_TYPE_LOCAL}</li>
-         * <li>{@link #PLAYBACK_TYPE_REMOTE}</li>
-         * </ul>
-         *
-         * @return The type of playback this session is using.
-         */
-        public int getPlaybackType() {
-            return mVolumeType;
-        }
-
-        /**
-         * Get the audio attributes for this session. The attributes will affect
-         * volume handling for the session. When the volume type is
-         * {@link PlaybackInfo#PLAYBACK_TYPE_REMOTE} these may be ignored by the
-         * remote volume handler.
-         *
-         * @return The attributes for this session.
-         */
-        public AudioAttributes getAudioAttributes() {
-            return mAudioAttrs;
-        }
-
-        /**
-         * Get the type of volume control that can be used. One of:
-         * <ul>
-         * <li>{@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}</li>
-         * <li>{@link VolumeProvider#VOLUME_CONTROL_RELATIVE}</li>
-         * <li>{@link VolumeProvider#VOLUME_CONTROL_FIXED}</li>
-         * </ul>
-         *
-         * @return The type of volume control that may be used with this
-         *         session.
-         */
-        public int getVolumeControl() {
-            return mVolumeControl;
-        }
-
-        /**
-         * Get the maximum volume that may be set for this session.
-         *
-         * @return The maximum allowed volume where this session is playing.
-         */
-        public int getMaxVolume() {
-            return mMaxVolume;
-        }
-
-        /**
-         * Get the current volume for this session.
-         *
-         * @return The current volume where this session is playing.
-         */
-        public int getCurrentVolume() {
-            return mCurrentVolume;
-        }
-    }
-
-    private final static class CallbackStub extends ISessionControllerCallback.Stub {
-        private final WeakReference<MediaController> mController;
-
-        public CallbackStub(MediaController controller) {
-            mController = new WeakReference<MediaController>(controller);
-        }
-
-        @Override
-        public void onSessionDestroyed() {
-            MediaController controller = mController.get();
-            if (controller != null) {
-                controller.postMessage(MSG_DESTROYED, null, null);
-            }
-        }
-
-        @Override
-        public void onEvent(String event, Bundle extras) {
-            MediaController controller = mController.get();
-            if (controller != null) {
-                controller.postMessage(MSG_EVENT, event, extras);
-            }
-        }
-
-        @Override
-        public void onPlaybackStateChanged(PlaybackState state) {
-            MediaController controller = mController.get();
-            if (controller != null) {
-                controller.postMessage(MSG_UPDATE_PLAYBACK_STATE, state, null);
-            }
-        }
-
-        @Override
-        public void onMetadataChanged(MediaMetadata metadata) {
-            MediaController controller = mController.get();
-            if (controller != null) {
-                controller.postMessage(MSG_UPDATE_METADATA, metadata, null);
-            }
-        }
-
-        @Override
-        public void onQueueChanged(MediaParceledListSlice parceledQueue) {
-            List<MediaSession.QueueItem> queue = parceledQueue == null ? null : parceledQueue
-                    .getList();
-            MediaController controller = mController.get();
-            if (controller != null) {
-                controller.postMessage(MSG_UPDATE_QUEUE, queue, null);
-            }
-        }
-
-        @Override
-        public void onQueueTitleChanged(CharSequence title) {
-            MediaController controller = mController.get();
-            if (controller != null) {
-                controller.postMessage(MSG_UPDATE_QUEUE_TITLE, title, null);
-            }
-        }
-
-        @Override
-        public void onExtrasChanged(Bundle extras) {
-            MediaController controller = mController.get();
-            if (controller != null) {
-                controller.postMessage(MSG_UPDATE_EXTRAS, extras, null);
-            }
-        }
-
-        @Override
-        public void onVolumeInfoChanged(ParcelableVolumeInfo pvi) {
-            MediaController controller = mController.get();
-            if (controller != null) {
-                PlaybackInfo info = new PlaybackInfo(pvi.volumeType, pvi.audioAttrs,
-                        pvi.controlType, pvi.maxVolume, pvi.currentVolume);
-                controller.postMessage(MSG_UPDATE_VOLUME, info, null);
-            }
-        }
-
-    }
-
-    private final static class MessageHandler extends Handler {
-        private final MediaController.Callback mCallback;
-        private boolean mRegistered = false;
-
-        public MessageHandler(Looper looper, MediaController.Callback cb) {
-            super(looper);
-            mCallback = cb;
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            if (!mRegistered) {
-                return;
-            }
-            switch (msg.what) {
-                case MSG_EVENT:
-                    mCallback.onSessionEvent((String) msg.obj, msg.getData());
-                    break;
-                case MSG_UPDATE_PLAYBACK_STATE:
-                    mCallback.onPlaybackStateChanged((PlaybackState) msg.obj);
-                    break;
-                case MSG_UPDATE_METADATA:
-                    mCallback.onMetadataChanged((MediaMetadata) msg.obj);
-                    break;
-                case MSG_UPDATE_QUEUE:
-                    mCallback.onQueueChanged((List<MediaSession.QueueItem>) msg.obj);
-                    break;
-                case MSG_UPDATE_QUEUE_TITLE:
-                    mCallback.onQueueTitleChanged((CharSequence) msg.obj);
-                    break;
-                case MSG_UPDATE_EXTRAS:
-                    mCallback.onExtrasChanged((Bundle) msg.obj);
-                    break;
-                case MSG_UPDATE_VOLUME:
-                    mCallback.onAudioInfoChanged((PlaybackInfo) msg.obj);
-                    break;
-                case MSG_DESTROYED:
-                    mCallback.onSessionDestroyed();
-                    break;
-            }
-        }
-
-        public void post(int what, Object obj, Bundle data) {
-            Message msg = obtainMessage(what, obj);
-            msg.setAsynchronous(true);
-            msg.setData(data);
-            msg.sendToTarget();
-        }
-    }
-
-}
diff --git a/packages/MediaComponents/apex/java/android/media/session/MediaSession.aidl b/packages/MediaComponents/apex/java/android/media/session/MediaSession.aidl
deleted file mode 100644
index f657cef..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/MediaSession.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/* Copyright 2014, 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.session;
-
-parcelable MediaSession.Token;
-parcelable MediaSession.QueueItem;
\ No newline at end of file
diff --git a/packages/MediaComponents/apex/java/android/media/session/MediaSession.java b/packages/MediaComponents/apex/java/android/media/session/MediaSession.java
deleted file mode 100644
index 3cbeff9..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/MediaSession.java
+++ /dev/null
@@ -1,1569 +0,0 @@
-/*
- * Copyright (C) 2014 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.session;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
-import android.app.Activity;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.media.AudioAttributes;
-import android.media.MediaDescription;
-import android.media.MediaMetadata;
-import android.media.MediaParceledListSlice;
-import android.media.Rating;
-import android.media.VolumeProvider;
-import android.media.session.MediaSessionManager.RemoteUserInfo;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.os.UserHandle;
-import android.service.media.MediaBrowserService;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.Pair;
-import android.view.KeyEvent;
-import android.view.ViewConfiguration;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.ref.WeakReference;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Allows interaction with media controllers, volume keys, media buttons, and
- * transport controls.
- * <p>
- * A MediaSession should be created when an app wants to publish media playback
- * information or handle media keys. In general an app only needs one session
- * for all playback, though multiple sessions can be created to provide finer
- * grain controls of media.
- * <p>
- * Once a session is created the owner of the session may pass its
- * {@link #getSessionToken() session token} to other processes to allow them to
- * create a {@link MediaController} to interact with the session.
- * <p>
- * To receive commands, media keys, and other events a {@link Callback} must be
- * set with {@link #setCallback(Callback)} and {@link #setActive(boolean)
- * setActive(true)} must be called.
- * <p>
- * When an app is finished performing playback it must call {@link #release()}
- * to clean up the session and notify any controllers.
- * <p>
- * MediaSession objects are thread safe.
- */
-public final class MediaSession {
-    private static final String TAG = "MediaSession";
-
-    /**
-     * Set this flag on the session to indicate that it can handle media button
-     * events.
-     * @deprecated This flag is no longer used. All media sessions are expected to handle media
-     * button events now.
-     */
-    @Deprecated
-    public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1 << 0;
-
-    /**
-     * Set this flag on the session to indicate that it handles transport
-     * control commands through its {@link Callback}.
-     * @deprecated This flag is no longer used. All media sessions are expected to handle transport
-     * controls now.
-     */
-    @Deprecated
-    public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 1 << 1;
-
-    /**
-     * System only flag for a session that needs to have priority over all other
-     * sessions. This flag ensures this session will receive media button events
-     * regardless of the current ordering in the system.
-     *
-     * @hide
-     */
-    public static final int FLAG_EXCLUSIVE_GLOBAL_PRIORITY = 1 << 16;
-
-    /**
-     * @hide
-     */
-    public static final int INVALID_UID = -1;
-
-    /**
-     * @hide
-     */
-    public static final int INVALID_PID = -1;
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag = true, value = {
-            FLAG_HANDLES_MEDIA_BUTTONS,
-            FLAG_HANDLES_TRANSPORT_CONTROLS,
-            FLAG_EXCLUSIVE_GLOBAL_PRIORITY })
-    public @interface SessionFlags { }
-
-    private final Object mLock = new Object();
-    private final int mMaxBitmapSize;
-
-    private final MediaSession.Token mSessionToken;
-    private final MediaController mController;
-    private final ISession mBinder;
-    private final CallbackStub mCbStub;
-
-    // Do not change the name of mCallback. Support lib accesses this by using reflection.
-    @UnsupportedAppUsage
-    private CallbackMessageHandler mCallback;
-    private VolumeProvider mVolumeProvider;
-    private PlaybackState mPlaybackState;
-
-    private boolean mActive = false;
-
-    /**
-     * Creates a new session. The session will automatically be registered with
-     * the system but will not be published until {@link #setActive(boolean)
-     * setActive(true)} is called. You must call {@link #release()} when
-     * finished with the session.
-     *
-     * @param context The context to use to create the session.
-     * @param tag A short name for debugging purposes.
-     */
-    public MediaSession(@NonNull Context context, @NonNull String tag) {
-        this(context, tag, UserHandle.myUserId());
-    }
-
-    /**
-     * Creates a new session as the specified user. To create a session as a
-     * user other than your own you must hold the
-     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}
-     * permission.
-     *
-     * @param context The context to use to create the session.
-     * @param tag A short name for debugging purposes.
-     * @param userId The user id to create the session as.
-     * @hide
-     */
-    public MediaSession(@NonNull Context context, @NonNull String tag, int userId) {
-        if (context == null) {
-            throw new IllegalArgumentException("context cannot be null.");
-        }
-        if (TextUtils.isEmpty(tag)) {
-            throw new IllegalArgumentException("tag cannot be null or empty");
-        }
-        mMaxBitmapSize = context.getResources().getDimensionPixelSize(
-                android.R.dimen.config_mediaMetadataBitmapMaxSize);
-        mCbStub = new CallbackStub(this);
-        MediaSessionManager manager = (MediaSessionManager) context
-                .getSystemService(Context.MEDIA_SESSION_SERVICE);
-        try {
-            //TODO(b/119749862): Resolve hidden API usage. MediaSessioManager#createSession
-            //mBinder = manager.createSession(mCbStub, tag, userId);
-            mBinder = null;  //TODO: remove this.
-            mSessionToken = new Token(mBinder.getController());
-            mController = new MediaController(context, mSessionToken);
-        } catch (RemoteException e) {
-            throw new RuntimeException("Remote error creating session.", e);
-        }
-    }
-
-    /**
-     * Set the callback to receive updates for the MediaSession. This includes
-     * media button events and transport controls. The caller's thread will be
-     * used to post updates.
-     * <p>
-     * Set the callback to null to stop receiving updates.
-     *
-     * @param callback The callback object
-     */
-    public void setCallback(@Nullable Callback callback) {
-        setCallback(callback, null);
-    }
-
-    /**
-     * Set the callback to receive updates for the MediaSession. This includes
-     * media button events and transport controls.
-     * <p>
-     * Set the callback to null to stop receiving updates.
-     *
-     * @param callback The callback to receive updates on.
-     * @param handler The handler that events should be posted on.
-     */
-    public void setCallback(@Nullable Callback callback, @Nullable Handler handler) {
-        synchronized (mLock) {
-            if (mCallback != null) {
-                // We're updating the callback, clear the session from the old one.
-                mCallback.mCallback.mSession = null;
-                mCallback.removeCallbacksAndMessages(null);
-            }
-            if (callback == null) {
-                mCallback = null;
-                return;
-            }
-            if (handler == null) {
-                handler = new Handler();
-            }
-            callback.mSession = this;
-            CallbackMessageHandler msgHandler = new CallbackMessageHandler(handler.getLooper(),
-                    callback);
-            mCallback = msgHandler;
-        }
-    }
-
-    /**
-     * Set an intent for launching UI for this Session. This can be used as a
-     * quick link to an ongoing media screen. The intent should be for an
-     * activity that may be started using {@link Activity#startActivity(Intent)}.
-     *
-     * @param pi The intent to launch to show UI for this Session.
-     */
-    public void setSessionActivity(@Nullable PendingIntent pi) {
-        try {
-            mBinder.setLaunchPendingIntent(pi);
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Failure in setLaunchPendingIntent.", e);
-        }
-    }
-
-    /**
-     * Set a pending intent for your media button receiver to allow restarting
-     * playback after the session has been stopped. If your app is started in
-     * this way an {@link Intent#ACTION_MEDIA_BUTTON} intent will be sent via
-     * the pending intent.
-     *
-     * @param mbr The {@link PendingIntent} to send the media button event to.
-     */
-    public void setMediaButtonReceiver(@Nullable PendingIntent mbr) {
-        try {
-            mBinder.setMediaButtonReceiver(mbr);
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Failure in setMediaButtonReceiver.", e);
-        }
-    }
-
-    /**
-     * Set any flags for the session.
-     *
-     * @param flags The flags to set for this session.
-     */
-    public void setFlags(@SessionFlags int flags) {
-        try {
-            mBinder.setFlags(flags);
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Failure in setFlags.", e);
-        }
-    }
-
-    /**
-     * Set the attributes for this session's audio. This will affect the
-     * system's volume handling for this session. If
-     * {@link #setPlaybackToRemote} was previously called it will stop receiving
-     * volume commands and the system will begin sending volume changes to the
-     * appropriate stream.
-     * <p>
-     * By default sessions use attributes for media.
-     *
-     * @param attributes The {@link AudioAttributes} for this session's audio.
-     */
-    public void setPlaybackToLocal(AudioAttributes attributes) {
-        if (attributes == null) {
-            throw new IllegalArgumentException("Attributes cannot be null for local playback.");
-        }
-        //TODO(b/119751592): Decide if AudioAttributes should be updated.
-        /*
-        try {
-            mBinder.setPlaybackToLocal(attributes);
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Failure in setPlaybackToLocal.", e);
-        }
-        */
-    }
-
-    /**
-     * Configure this session to use remote volume handling. This must be called
-     * to receive volume button events, otherwise the system will adjust the
-     * appropriate stream volume for this session. If
-     * {@link #setPlaybackToLocal} was previously called the system will stop
-     * handling volume changes for this session and pass them to the volume
-     * provider instead.
-     *
-     * @param volumeProvider The provider that will handle volume changes. May
-     *            not be null.
-     */
-    public void setPlaybackToRemote(@NonNull VolumeProvider volumeProvider) {
-        if (volumeProvider == null) {
-            throw new IllegalArgumentException("volumeProvider may not be null!");
-        }
-        synchronized (mLock) {
-            mVolumeProvider = volumeProvider;
-        }
-        volumeProvider.setCallback(new VolumeProvider.Callback() {
-            @Override
-            public void onVolumeChanged(VolumeProvider volumeProvider) {
-                notifyRemoteVolumeChanged(volumeProvider);
-            }
-        });
-
-        try {
-            mBinder.setPlaybackToRemote(volumeProvider.getVolumeControl(),
-                    volumeProvider.getMaxVolume());
-            mBinder.setCurrentVolume(volumeProvider.getCurrentVolume());
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Failure in setPlaybackToRemote.", e);
-        }
-    }
-
-    /**
-     * Set if this session is currently active and ready to receive commands. If
-     * set to false your session's controller may not be discoverable. You must
-     * set the session to active before it can start receiving media button
-     * events or transport commands.
-     *
-     * @param active Whether this session is active or not.
-     */
-    public void setActive(boolean active) {
-        if (mActive == active) {
-            return;
-        }
-        try {
-            mBinder.setActive(active);
-            mActive = active;
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Failure in setActive.", e);
-        }
-    }
-
-    /**
-     * Get the current active state of this session.
-     *
-     * @return True if the session is active, false otherwise.
-     */
-    public boolean isActive() {
-        return mActive;
-    }
-
-    /**
-     * Send a proprietary event to all MediaControllers listening to this
-     * Session. It's up to the Controller/Session owner to determine the meaning
-     * of any events.
-     *
-     * @param event The name of the event to send
-     * @param extras Any extras included with the event
-     */
-    public void sendSessionEvent(@NonNull String event, @Nullable Bundle extras) {
-        if (TextUtils.isEmpty(event)) {
-            throw new IllegalArgumentException("event cannot be null or empty");
-        }
-        try {
-            mBinder.sendEvent(event, extras);
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error sending event", e);
-        }
-    }
-
-    /**
-     * This must be called when an app has finished performing playback. If
-     * playback is expected to start again shortly the session can be left open,
-     * but it must be released if your activity or service is being destroyed.
-     */
-    public void release() {
-        try {
-            mBinder.destroy();
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error releasing session: ", e);
-        }
-    }
-
-    /**
-     * Retrieve a token object that can be used by apps to create a
-     * {@link MediaController} for interacting with this session. The owner of
-     * the session is responsible for deciding how to distribute these tokens.
-     *
-     * @return A token that can be used to create a MediaController for this
-     *         session
-     */
-    public @NonNull Token getSessionToken() {
-        return mSessionToken;
-    }
-
-    /**
-     * Get a controller for this session. This is a convenience method to avoid
-     * having to cache your own controller in process.
-     *
-     * @return A controller for this session.
-     */
-    public @NonNull MediaController getController() {
-        return mController;
-    }
-
-    /**
-     * Update the current playback state.
-     *
-     * @param state The current state of playback
-     */
-    public void setPlaybackState(@Nullable PlaybackState state) {
-        mPlaybackState = state;
-        try {
-            mBinder.setPlaybackState(state);
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Dead object in setPlaybackState.", e);
-        }
-    }
-
-    /**
-     * Update the current metadata. New metadata can be created using
-     * {@link android.media.MediaMetadata.Builder}. This operation may take time proportional to
-     * the size of the bitmap to replace large bitmaps with a scaled down copy.
-     *
-     * @param metadata The new metadata
-     * @see android.media.MediaMetadata.Builder#putBitmap
-     */
-    public void setMetadata(@Nullable MediaMetadata metadata) {
-        long duration = -1;
-        int fields = 0;
-        MediaDescription description = null;
-        if (metadata != null) {
-            metadata = (new MediaMetadata.Builder(metadata, mMaxBitmapSize)).build();
-            if (metadata.containsKey(MediaMetadata.METADATA_KEY_DURATION)) {
-                duration = metadata.getLong(MediaMetadata.METADATA_KEY_DURATION);
-            }
-            fields = metadata.size();
-            description = metadata.getDescription();
-        }
-        String metadataDescription = "size=" + fields + ", description=" + description;
-
-        try {
-            mBinder.setMetadata(metadata, duration, metadataDescription);
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Dead object in setPlaybackState.", e);
-        }
-    }
-
-    /**
-     * Update the list of items in the play queue. It is an ordered list and
-     * should contain the current item, and previous or upcoming items if they
-     * exist. Specify null if there is no current play queue.
-     * <p>
-     * The queue should be of reasonable size. If the play queue is unbounded
-     * within your app, it is better to send a reasonable amount in a sliding
-     * window instead.
-     *
-     * @param queue A list of items in the play queue.
-     */
-    public void setQueue(@Nullable List<QueueItem> queue) {
-        try {
-            mBinder.setQueue(queue == null ? null : new MediaParceledListSlice<QueueItem>(queue));
-        } catch (RemoteException e) {
-            Log.wtf("Dead object in setQueue.", e);
-        }
-    }
-
-    /**
-     * Set the title of the play queue. The UI should display this title along
-     * with the play queue itself.
-     * e.g. "Play Queue", "Now Playing", or an album name.
-     *
-     * @param title The title of the play queue.
-     */
-    public void setQueueTitle(@Nullable CharSequence title) {
-        try {
-            mBinder.setQueueTitle(title);
-        } catch (RemoteException e) {
-            Log.wtf("Dead object in setQueueTitle.", e);
-        }
-    }
-
-    /**
-     * Set the style of rating used by this session. Apps trying to set the
-     * rating should use this style. Must be one of the following:
-     * <ul>
-     * <li>{@link Rating#RATING_NONE}</li>
-     * <li>{@link Rating#RATING_3_STARS}</li>
-     * <li>{@link Rating#RATING_4_STARS}</li>
-     * <li>{@link Rating#RATING_5_STARS}</li>
-     * <li>{@link Rating#RATING_HEART}</li>
-     * <li>{@link Rating#RATING_PERCENTAGE}</li>
-     * <li>{@link Rating#RATING_THUMB_UP_DOWN}</li>
-     * </ul>
-     */
-    public void setRatingType(@Rating.Style int type) {
-        try {
-            mBinder.setRatingType(type);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error in setRatingType.", e);
-        }
-    }
-
-    /**
-     * Set some extras that can be associated with the {@link MediaSession}. No assumptions should
-     * be made as to how a {@link MediaController} will handle these extras.
-     * Keys should be fully qualified (e.g. com.example.MY_EXTRA) to avoid conflicts.
-     *
-     * @param extras The extras associated with the {@link MediaSession}.
-     */
-    public void setExtras(@Nullable Bundle extras) {
-        try {
-            mBinder.setExtras(extras);
-        } catch (RemoteException e) {
-            Log.wtf("Dead object in setExtras.", e);
-        }
-    }
-
-    /**
-     * Gets the controller information who sent the current request.
-     * <p>
-     * Note: This is only valid while in a request callback, such as {@link Callback#onPlay}.
-     *
-     * @throws IllegalStateException If this method is called outside of {@link Callback} methods.
-     * @see MediaSessionManager#isTrustedForMediaControl(RemoteUserInfo)
-     */
-    public final @NonNull RemoteUserInfo getCurrentControllerInfo() {
-        if (mCallback == null || mCallback.mCurrentControllerInfo == null) {
-            throw new IllegalStateException(
-                    "This should be called inside of MediaSession.Callback methods");
-        }
-        return mCallback.mCurrentControllerInfo;
-    }
-
-    /**
-     * Notify the system that the remote volume changed.
-     *
-     * @param provider The provider that is handling volume changes.
-     * @hide
-     */
-    public void notifyRemoteVolumeChanged(VolumeProvider provider) {
-        synchronized (mLock) {
-            if (provider == null || provider != mVolumeProvider) {
-                Log.w(TAG, "Received update from stale volume provider");
-                return;
-            }
-        }
-        try {
-            mBinder.setCurrentVolume(provider.getCurrentVolume());
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error in notifyVolumeChanged", e);
-        }
-    }
-
-    /**
-     * Returns the name of the package that sent the last media button, transport control, or
-     * command from controllers and the system. This is only valid while in a request callback, such
-     * as {@link Callback#onPlay}.
-     *
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public String getCallingPackage() {
-        if (mCallback != null && mCallback.mCurrentControllerInfo != null) {
-            return mCallback.mCurrentControllerInfo.getPackageName();
-        }
-        return null;
-    }
-
-    private void dispatchPrepare(RemoteUserInfo caller) {
-        postToCallback(caller, CallbackMessageHandler.MSG_PREPARE, null, null);
-    }
-
-    private void dispatchPrepareFromMediaId(RemoteUserInfo caller, String mediaId, Bundle extras) {
-        postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_MEDIA_ID, mediaId, extras);
-    }
-
-    private void dispatchPrepareFromSearch(RemoteUserInfo caller, String query, Bundle extras) {
-        postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_SEARCH, query, extras);
-    }
-
-    private void dispatchPrepareFromUri(RemoteUserInfo caller, Uri uri, Bundle extras) {
-        postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_URI, uri, extras);
-    }
-
-    private void dispatchPlay(RemoteUserInfo caller) {
-        postToCallback(caller, CallbackMessageHandler.MSG_PLAY, null, null);
-    }
-
-    private void dispatchPlayFromMediaId(RemoteUserInfo caller, String mediaId, Bundle extras) {
-        postToCallback(caller, CallbackMessageHandler.MSG_PLAY_MEDIA_ID, mediaId, extras);
-    }
-
-    private void dispatchPlayFromSearch(RemoteUserInfo caller, String query, Bundle extras) {
-        postToCallback(caller, CallbackMessageHandler.MSG_PLAY_SEARCH, query, extras);
-    }
-
-    private void dispatchPlayFromUri(RemoteUserInfo caller, Uri uri, Bundle extras) {
-        postToCallback(caller, CallbackMessageHandler.MSG_PLAY_URI, uri, extras);
-    }
-
-    private void dispatchSkipToItem(RemoteUserInfo caller, long id) {
-        postToCallback(caller, CallbackMessageHandler.MSG_SKIP_TO_ITEM, id, null);
-    }
-
-    private void dispatchPause(RemoteUserInfo caller) {
-        postToCallback(caller, CallbackMessageHandler.MSG_PAUSE, null, null);
-    }
-
-    private void dispatchStop(RemoteUserInfo caller) {
-        postToCallback(caller, CallbackMessageHandler.MSG_STOP, null, null);
-    }
-
-    private void dispatchNext(RemoteUserInfo caller) {
-        postToCallback(caller, CallbackMessageHandler.MSG_NEXT, null, null);
-    }
-
-    private void dispatchPrevious(RemoteUserInfo caller) {
-        postToCallback(caller, CallbackMessageHandler.MSG_PREVIOUS, null, null);
-    }
-
-    private void dispatchFastForward(RemoteUserInfo caller) {
-        postToCallback(caller, CallbackMessageHandler.MSG_FAST_FORWARD, null, null);
-    }
-
-    private void dispatchRewind(RemoteUserInfo caller) {
-        postToCallback(caller, CallbackMessageHandler.MSG_REWIND, null, null);
-    }
-
-    private void dispatchSeekTo(RemoteUserInfo caller, long pos) {
-        postToCallback(caller, CallbackMessageHandler.MSG_SEEK_TO, pos, null);
-    }
-
-    private void dispatchRate(RemoteUserInfo caller, Rating rating) {
-        postToCallback(caller, CallbackMessageHandler.MSG_RATE, rating, null);
-    }
-
-    private void dispatchCustomAction(RemoteUserInfo caller, String action, Bundle args) {
-        postToCallback(caller, CallbackMessageHandler.MSG_CUSTOM_ACTION, action, args);
-    }
-
-    private void dispatchMediaButton(RemoteUserInfo caller, Intent mediaButtonIntent) {
-        postToCallback(caller, CallbackMessageHandler.MSG_MEDIA_BUTTON, mediaButtonIntent, null);
-    }
-
-    private void dispatchMediaButtonDelayed(RemoteUserInfo info, Intent mediaButtonIntent,
-            long delay) {
-        postToCallbackDelayed(info, CallbackMessageHandler.MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT,
-                mediaButtonIntent, null, delay);
-    }
-
-    private void dispatchAdjustVolume(RemoteUserInfo caller, int direction) {
-        postToCallback(caller, CallbackMessageHandler.MSG_ADJUST_VOLUME, direction, null);
-    }
-
-    private void dispatchSetVolumeTo(RemoteUserInfo caller, int volume) {
-        postToCallback(caller, CallbackMessageHandler.MSG_SET_VOLUME, volume, null);
-    }
-
-    private void dispatchCommand(RemoteUserInfo caller, String command, Bundle args,
-            ResultReceiver resultCb) {
-        Command cmd = new Command(command, args, resultCb);
-        postToCallback(caller, CallbackMessageHandler.MSG_COMMAND, cmd, null);
-    }
-
-    private void postToCallback(RemoteUserInfo caller, int what, Object obj, Bundle data) {
-        postToCallbackDelayed(caller, what, obj, data, 0);
-    }
-
-    private void postToCallbackDelayed(RemoteUserInfo caller, int what, Object obj, Bundle data,
-            long delay) {
-        synchronized (mLock) {
-            if (mCallback != null) {
-                mCallback.post(caller, what, obj, data, delay);
-            }
-        }
-    }
-
-    /**
-     * Return true if this is considered an active playback state.
-     *
-     * @hide
-     */
-    public static boolean isActiveState(int state) {
-        switch (state) {
-            case PlaybackState.STATE_FAST_FORWARDING:
-            case PlaybackState.STATE_REWINDING:
-            case PlaybackState.STATE_SKIPPING_TO_PREVIOUS:
-            case PlaybackState.STATE_SKIPPING_TO_NEXT:
-            case PlaybackState.STATE_BUFFERING:
-            case PlaybackState.STATE_CONNECTING:
-            case PlaybackState.STATE_PLAYING:
-                return true;
-        }
-        return false;
-    }
-
-    /**
-     * Represents an ongoing session. This may be passed to apps by the session
-     * owner to allow them to create a {@link MediaController} to communicate with
-     * the session.
-     */
-    public static final class Token implements Parcelable {
-
-        private ISessionController mBinder;
-
-        /**
-         * @hide
-         */
-        public Token(ISessionController binder) {
-            mBinder = binder;
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            dest.writeStrongBinder(mBinder.asBinder());
-        }
-
-        @Override
-        public int hashCode() {
-            final int prime = 31;
-            int result = 1;
-            result = prime * result + ((mBinder == null) ? 0 : mBinder.asBinder().hashCode());
-            return result;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj)
-                return true;
-            if (obj == null)
-                return false;
-            if (getClass() != obj.getClass())
-                return false;
-            Token other = (Token) obj;
-            if (mBinder == null) {
-                if (other.mBinder != null)
-                    return false;
-            } else if (!mBinder.asBinder().equals(other.mBinder.asBinder()))
-                return false;
-            return true;
-        }
-
-        ISessionController getBinder() {
-            return mBinder;
-        }
-
-        public static final Parcelable.Creator<Token> CREATOR
-                = new Parcelable.Creator<Token>() {
-            @Override
-            public Token createFromParcel(Parcel in) {
-                return new Token(ISessionController.Stub.asInterface(in.readStrongBinder()));
-            }
-
-            @Override
-            public Token[] newArray(int size) {
-                return new Token[size];
-            }
-        };
-    }
-
-    /**
-     * Receives media buttons, transport controls, and commands from controllers
-     * and the system. A callback may be set using {@link #setCallback}.
-     */
-    public abstract static class Callback {
-
-        private MediaSession mSession;
-        private CallbackMessageHandler mHandler;
-        private boolean mMediaPlayPauseKeyPending;
-
-        public Callback() {
-        }
-
-        /**
-         * Called when a controller has sent a command to this session.
-         * The owner of the session may handle custom commands but is not
-         * required to.
-         *
-         * @param command The command name.
-         * @param args Optional parameters for the command, may be null.
-         * @param cb A result receiver to which a result may be sent by the command, may be null.
-         */
-        public void onCommand(@NonNull String command, @Nullable Bundle args,
-                @Nullable ResultReceiver cb) {
-        }
-
-        /**
-         * Called when a media button is pressed and this session has the
-         * highest priority or a controller sends a media button event to the
-         * session. The default behavior will call the relevant method if the
-         * action for it was set.
-         * <p>
-         * The intent will be of type {@link Intent#ACTION_MEDIA_BUTTON} with a
-         * KeyEvent in {@link Intent#EXTRA_KEY_EVENT}
-         *
-         * @param mediaButtonIntent an intent containing the KeyEvent as an
-         *            extra
-         * @return True if the event was handled, false otherwise.
-         */
-        public boolean onMediaButtonEvent(@NonNull Intent mediaButtonIntent) {
-            if (mSession != null && mHandler != null
-                    && Intent.ACTION_MEDIA_BUTTON.equals(mediaButtonIntent.getAction())) {
-                KeyEvent ke = mediaButtonIntent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
-                if (ke != null && ke.getAction() == KeyEvent.ACTION_DOWN) {
-                    PlaybackState state = mSession.mPlaybackState;
-                    long validActions = state == null ? 0 : state.getActions();
-                    switch (ke.getKeyCode()) {
-                        case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
-                        case KeyEvent.KEYCODE_HEADSETHOOK:
-                            if (ke.getRepeatCount() > 0) {
-                                // Consider long-press as a single tap.
-                                handleMediaPlayPauseKeySingleTapIfPending();
-                            } else if (mMediaPlayPauseKeyPending) {
-                                // Consider double tap as the next.
-                                mHandler.removeMessages(CallbackMessageHandler
-                                        .MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT);
-                                mMediaPlayPauseKeyPending = false;
-                                if ((validActions & PlaybackState.ACTION_SKIP_TO_NEXT) != 0) {
-                                    onSkipToNext();
-                                }
-                            } else {
-                                mMediaPlayPauseKeyPending = true;
-                                mSession.dispatchMediaButtonDelayed(
-                                        mSession.getCurrentControllerInfo(),
-                                        mediaButtonIntent, ViewConfiguration.getDoubleTapTimeout());
-                            }
-                            return true;
-                        default:
-                            // If another key is pressed within double tap timeout, consider the
-                            // pending play/pause as a single tap to handle media keys in order.
-                            handleMediaPlayPauseKeySingleTapIfPending();
-                            break;
-                    }
-
-                    switch (ke.getKeyCode()) {
-                        case KeyEvent.KEYCODE_MEDIA_PLAY:
-                            if ((validActions & PlaybackState.ACTION_PLAY) != 0) {
-                                onPlay();
-                                return true;
-                            }
-                            break;
-                        case KeyEvent.KEYCODE_MEDIA_PAUSE:
-                            if ((validActions & PlaybackState.ACTION_PAUSE) != 0) {
-                                onPause();
-                                return true;
-                            }
-                            break;
-                        case KeyEvent.KEYCODE_MEDIA_NEXT:
-                            if ((validActions & PlaybackState.ACTION_SKIP_TO_NEXT) != 0) {
-                                onSkipToNext();
-                                return true;
-                            }
-                            break;
-                        case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
-                            if ((validActions & PlaybackState.ACTION_SKIP_TO_PREVIOUS) != 0) {
-                                onSkipToPrevious();
-                                return true;
-                            }
-                            break;
-                        case KeyEvent.KEYCODE_MEDIA_STOP:
-                            if ((validActions & PlaybackState.ACTION_STOP) != 0) {
-                                onStop();
-                                return true;
-                            }
-                            break;
-                        case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
-                            if ((validActions & PlaybackState.ACTION_FAST_FORWARD) != 0) {
-                                onFastForward();
-                                return true;
-                            }
-                            break;
-                        case KeyEvent.KEYCODE_MEDIA_REWIND:
-                            if ((validActions & PlaybackState.ACTION_REWIND) != 0) {
-                                onRewind();
-                                return true;
-                            }
-                            break;
-                    }
-                }
-            }
-            return false;
-        }
-
-        private void handleMediaPlayPauseKeySingleTapIfPending() {
-            if (!mMediaPlayPauseKeyPending) {
-                return;
-            }
-            mMediaPlayPauseKeyPending = false;
-            mHandler.removeMessages(CallbackMessageHandler.MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT);
-            PlaybackState state = mSession.mPlaybackState;
-            long validActions = state == null ? 0 : state.getActions();
-            boolean isPlaying = state != null
-                    && state.getState() == PlaybackState.STATE_PLAYING;
-            boolean canPlay = (validActions & (PlaybackState.ACTION_PLAY_PAUSE
-                        | PlaybackState.ACTION_PLAY)) != 0;
-            boolean canPause = (validActions & (PlaybackState.ACTION_PLAY_PAUSE
-                        | PlaybackState.ACTION_PAUSE)) != 0;
-            if (isPlaying && canPause) {
-                onPause();
-            } else if (!isPlaying && canPlay) {
-                onPlay();
-            }
-        }
-
-        /**
-         * Override to handle requests to prepare playback. During the preparation, a session should
-         * not hold audio focus in order to allow other sessions play seamlessly. The state of
-         * playback should be updated to {@link PlaybackState#STATE_PAUSED} after the preparation is
-         * done.
-         */
-        public void onPrepare() {
-        }
-
-        /**
-         * Override to handle requests to prepare for playing a specific mediaId that was provided
-         * by your app's {@link MediaBrowserService}. During the preparation, a session should not
-         * hold audio focus in order to allow other sessions play seamlessly. The state of playback
-         * should be updated to {@link PlaybackState#STATE_PAUSED} after the preparation is done.
-         * The playback of the prepared content should start in the implementation of
-         * {@link #onPlay}. Override {@link #onPlayFromMediaId} to handle requests for starting
-         * playback without preparation.
-         */
-        public void onPrepareFromMediaId(String mediaId, Bundle extras) {
-        }
-
-        /**
-         * Override to handle requests to prepare playback from a search query. An empty query
-         * indicates that the app may prepare any music. The implementation should attempt to make a
-         * smart choice about what to play. During the preparation, a session should not hold audio
-         * focus in order to allow other sessions play seamlessly. The state of playback should be
-         * updated to {@link PlaybackState#STATE_PAUSED} after the preparation is done. The playback
-         * of the prepared content should start in the implementation of {@link #onPlay}. Override
-         * {@link #onPlayFromSearch} to handle requests for starting playback without preparation.
-         */
-        public void onPrepareFromSearch(String query, Bundle extras) {
-        }
-
-        /**
-         * Override to handle requests to prepare a specific media item represented by a URI.
-         * During the preparation, a session should not hold audio focus in order to allow
-         * other sessions play seamlessly. The state of playback should be updated to
-         * {@link PlaybackState#STATE_PAUSED} after the preparation is done.
-         * The playback of the prepared content should start in the implementation of
-         * {@link #onPlay}. Override {@link #onPlayFromUri} to handle requests
-         * for starting playback without preparation.
-         */
-        public void onPrepareFromUri(Uri uri, Bundle extras) {
-        }
-
-        /**
-         * Override to handle requests to begin playback.
-         */
-        public void onPlay() {
-        }
-
-        /**
-         * Override to handle requests to begin playback from a search query. An
-         * empty query indicates that the app may play any music. The
-         * implementation should attempt to make a smart choice about what to
-         * play.
-         */
-        public void onPlayFromSearch(String query, Bundle extras) {
-        }
-
-        /**
-         * Override to handle requests to play a specific mediaId that was
-         * provided by your app's {@link MediaBrowserService}.
-         */
-        public void onPlayFromMediaId(String mediaId, Bundle extras) {
-        }
-
-        /**
-         * Override to handle requests to play a specific media item represented by a URI.
-         */
-        public void onPlayFromUri(Uri uri, Bundle extras) {
-        }
-
-        /**
-         * Override to handle requests to play an item with a given id from the
-         * play queue.
-         */
-        public void onSkipToQueueItem(long id) {
-        }
-
-        /**
-         * Override to handle requests to pause playback.
-         */
-        public void onPause() {
-        }
-
-        /**
-         * Override to handle requests to skip to the next media item.
-         */
-        public void onSkipToNext() {
-        }
-
-        /**
-         * Override to handle requests to skip to the previous media item.
-         */
-        public void onSkipToPrevious() {
-        }
-
-        /**
-         * Override to handle requests to fast forward.
-         */
-        public void onFastForward() {
-        }
-
-        /**
-         * Override to handle requests to rewind.
-         */
-        public void onRewind() {
-        }
-
-        /**
-         * Override to handle requests to stop playback.
-         */
-        public void onStop() {
-        }
-
-        /**
-         * Override to handle requests to seek to a specific position in ms.
-         *
-         * @param pos New position to move to, in milliseconds.
-         */
-        public void onSeekTo(long pos) {
-        }
-
-        /**
-         * Override to handle the item being rated.
-         *
-         * @param rating
-         */
-        public void onSetRating(@NonNull Rating rating) {
-        }
-
-        /**
-         * Called when a {@link MediaController} wants a {@link PlaybackState.CustomAction} to be
-         * performed.
-         *
-         * @param action The action that was originally sent in the
-         *               {@link PlaybackState.CustomAction}.
-         * @param extras Optional extras specified by the {@link MediaController}.
-         */
-        public void onCustomAction(@NonNull String action, @Nullable Bundle extras) {
-        }
-    }
-
-    /**
-     * @hide
-     */
-    public static class CallbackStub extends ISessionCallback.Stub {
-        private WeakReference<MediaSession> mMediaSession;
-
-        public CallbackStub(MediaSession session) {
-            mMediaSession = new WeakReference<>(session);
-        }
-
-        private static RemoteUserInfo createRemoteUserInfo(String packageName, int pid, int uid,
-                ISessionControllerCallback caller) {
-            return new RemoteUserInfo(packageName, pid, uid);
-        }
-
-        @Override
-        public void onCommand(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, String command, Bundle args, ResultReceiver cb) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchCommand(createRemoteUserInfo(packageName, pid, uid, caller),
-                        command, args, cb);
-            }
-        }
-
-        @Override
-        public void onMediaButton(String packageName, int pid, int uid, Intent mediaButtonIntent,
-                int sequenceNumber, ResultReceiver cb) {
-            MediaSession session = mMediaSession.get();
-            try {
-                if (session != null) {
-                    session.dispatchMediaButton(createRemoteUserInfo(packageName, pid, uid, null),
-                            mediaButtonIntent);
-                }
-            } finally {
-                if (cb != null) {
-                    cb.send(sequenceNumber, null);
-                }
-            }
-        }
-
-        @Override
-        public void onMediaButtonFromController(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, Intent mediaButtonIntent) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchMediaButton(createRemoteUserInfo(packageName, pid, uid, caller),
-                        mediaButtonIntent);
-            }
-        }
-
-        @Override
-        public void onPrepare(String packageName, int pid, int uid,
-                ISessionControllerCallback caller) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchPrepare(createRemoteUserInfo(packageName, pid, uid, caller));
-            }
-        }
-
-        @Override
-        public void onPrepareFromMediaId(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, String mediaId,
-                Bundle extras) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchPrepareFromMediaId(
-                        createRemoteUserInfo(packageName, pid, uid, caller), mediaId, extras);
-            }
-        }
-
-        @Override
-        public void onPrepareFromSearch(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, String query,
-                Bundle extras) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchPrepareFromSearch(
-                        createRemoteUserInfo(packageName, pid, uid, caller), query, extras);
-            }
-        }
-
-        @Override
-        public void onPrepareFromUri(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, Uri uri, Bundle extras) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchPrepareFromUri(createRemoteUserInfo(packageName, pid, uid, caller),
-                        uri, extras);
-            }
-        }
-
-        @Override
-        public void onPlay(String packageName, int pid, int uid,
-                ISessionControllerCallback caller) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchPlay(createRemoteUserInfo(packageName, pid, uid, caller));
-            }
-        }
-
-        @Override
-        public void onPlayFromMediaId(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, String mediaId,
-                Bundle extras) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchPlayFromMediaId(createRemoteUserInfo(packageName, pid, uid, caller),
-                        mediaId, extras);
-            }
-        }
-
-        @Override
-        public void onPlayFromSearch(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, String query,
-                Bundle extras) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchPlayFromSearch(createRemoteUserInfo(packageName, pid, uid, caller),
-                        query, extras);
-            }
-        }
-
-        @Override
-        public void onPlayFromUri(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, Uri uri, Bundle extras) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchPlayFromUri(createRemoteUserInfo(packageName, pid, uid, caller),
-                        uri, extras);
-            }
-        }
-
-        @Override
-        public void onSkipToTrack(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, long id) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchSkipToItem(createRemoteUserInfo(packageName, pid, uid, caller), id);
-            }
-        }
-
-        @Override
-        public void onPause(String packageName, int pid, int uid,
-                ISessionControllerCallback caller) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchPause(createRemoteUserInfo(packageName, pid, uid, caller));
-            }
-        }
-
-        @Override
-        public void onStop(String packageName, int pid, int uid,
-                ISessionControllerCallback caller) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchStop(createRemoteUserInfo(packageName, pid, uid, caller));
-            }
-        }
-
-        @Override
-        public void onNext(String packageName, int pid, int uid,
-                ISessionControllerCallback caller) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchNext(createRemoteUserInfo(packageName, pid, uid, caller));
-            }
-        }
-
-        @Override
-        public void onPrevious(String packageName, int pid, int uid,
-                ISessionControllerCallback caller) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchPrevious(createRemoteUserInfo(packageName, pid, uid, caller));
-            }
-        }
-
-        @Override
-        public void onFastForward(String packageName, int pid, int uid,
-                ISessionControllerCallback caller) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchFastForward(createRemoteUserInfo(packageName, pid, uid, caller));
-            }
-        }
-
-        @Override
-        public void onRewind(String packageName, int pid, int uid,
-                ISessionControllerCallback caller) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchRewind(createRemoteUserInfo(packageName, pid, uid, caller));
-            }
-        }
-
-        @Override
-        public void onSeekTo(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, long pos) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchSeekTo(createRemoteUserInfo(packageName, pid, uid, caller), pos);
-            }
-        }
-
-        @Override
-        public void onRate(String packageName, int pid, int uid, ISessionControllerCallback caller,
-                Rating rating) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchRate(createRemoteUserInfo(packageName, pid, uid, caller), rating);
-            }
-        }
-
-        @Override
-        public void onCustomAction(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, String action, Bundle args) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchCustomAction(createRemoteUserInfo(packageName, pid, uid, caller),
-                        action, args);
-            }
-        }
-
-        @Override
-        public void onAdjustVolume(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, int direction) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchAdjustVolume(createRemoteUserInfo(packageName, pid, uid, caller),
-                        direction);
-            }
-        }
-
-        @Override
-        public void onSetVolumeTo(String packageName, int pid, int uid,
-                ISessionControllerCallback caller, int value) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchSetVolumeTo(createRemoteUserInfo(packageName, pid, uid, caller),
-                        value);
-            }
-        }
-    }
-
-    /**
-     * A single item that is part of the play queue. It contains a description
-     * of the item and its id in the queue.
-     */
-    public static final class QueueItem implements Parcelable {
-        /**
-         * This id is reserved. No items can be explicitly assigned this id.
-         */
-        public static final int UNKNOWN_ID = -1;
-
-        private final MediaDescription mDescription;
-        @UnsupportedAppUsage
-        private final long mId;
-
-        /**
-         * Create a new {@link MediaSession.QueueItem}.
-         *
-         * @param description The {@link MediaDescription} for this item.
-         * @param id An identifier for this item. It must be unique within the
-         *            play queue and cannot be {@link #UNKNOWN_ID}.
-         */
-        public QueueItem(MediaDescription description, long id) {
-            if (description == null) {
-                throw new IllegalArgumentException("Description cannot be null.");
-            }
-            if (id == UNKNOWN_ID) {
-                throw new IllegalArgumentException("Id cannot be QueueItem.UNKNOWN_ID");
-            }
-            mDescription = description;
-            mId = id;
-        }
-
-        private QueueItem(Parcel in) {
-            mDescription = MediaDescription.CREATOR.createFromParcel(in);
-            mId = in.readLong();
-        }
-
-        /**
-         * Get the description for this item.
-         */
-        public MediaDescription getDescription() {
-            return mDescription;
-        }
-
-        /**
-         * Get the queue id for this item.
-         */
-        public long getQueueId() {
-            return mId;
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            mDescription.writeToParcel(dest, flags);
-            dest.writeLong(mId);
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        public static final Creator<MediaSession.QueueItem> CREATOR =
-                new Creator<MediaSession.QueueItem>() {
-
-            @Override
-            public MediaSession.QueueItem createFromParcel(Parcel p) {
-                return new MediaSession.QueueItem(p);
-            }
-
-            @Override
-            public MediaSession.QueueItem[] newArray(int size) {
-                return new MediaSession.QueueItem[size];
-            }
-        };
-
-        @Override
-        public String toString() {
-            return "MediaSession.QueueItem {" +
-                    "Description=" + mDescription +
-                    ", Id=" + mId + " }";
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (o == null) {
-                return false;
-            }
-
-            if (!(o instanceof QueueItem)) {
-                return false;
-            }
-
-            final QueueItem item = (QueueItem) o;
-            if (mId != item.mId) {
-                return false;
-            }
-
-            if (!Objects.equals(mDescription, item.mDescription)) {
-                return false;
-            }
-
-            return true;
-        }
-    }
-
-    private static final class Command {
-        public final String command;
-        public final Bundle extras;
-        public final ResultReceiver stub;
-
-        public Command(String command, Bundle extras, ResultReceiver stub) {
-            this.command = command;
-            this.extras = extras;
-            this.stub = stub;
-        }
-    }
-
-    private class CallbackMessageHandler extends Handler {
-        private static final int MSG_COMMAND = 1;
-        private static final int MSG_MEDIA_BUTTON = 2;
-        private static final int MSG_PREPARE = 3;
-        private static final int MSG_PREPARE_MEDIA_ID = 4;
-        private static final int MSG_PREPARE_SEARCH = 5;
-        private static final int MSG_PREPARE_URI = 6;
-        private static final int MSG_PLAY = 7;
-        private static final int MSG_PLAY_MEDIA_ID = 8;
-        private static final int MSG_PLAY_SEARCH = 9;
-        private static final int MSG_PLAY_URI = 10;
-        private static final int MSG_SKIP_TO_ITEM = 11;
-        private static final int MSG_PAUSE = 12;
-        private static final int MSG_STOP = 13;
-        private static final int MSG_NEXT = 14;
-        private static final int MSG_PREVIOUS = 15;
-        private static final int MSG_FAST_FORWARD = 16;
-        private static final int MSG_REWIND = 17;
-        private static final int MSG_SEEK_TO = 18;
-        private static final int MSG_RATE = 19;
-        private static final int MSG_CUSTOM_ACTION = 20;
-        private static final int MSG_ADJUST_VOLUME = 21;
-        private static final int MSG_SET_VOLUME = 22;
-        private static final int MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT = 23;
-
-        private MediaSession.Callback mCallback;
-        private RemoteUserInfo mCurrentControllerInfo;
-
-        public CallbackMessageHandler(Looper looper, MediaSession.Callback callback) {
-            super(looper);
-            mCallback = callback;
-            mCallback.mHandler = this;
-        }
-
-        public void post(RemoteUserInfo caller, int what, Object obj, Bundle data, long delayMs) {
-            Pair<RemoteUserInfo, Object> objWithCaller = Pair.create(caller, obj);
-            Message msg = obtainMessage(what, objWithCaller);
-            msg.setAsynchronous(true);
-            msg.setData(data);
-            if (delayMs > 0) {
-                sendMessageDelayed(msg, delayMs);
-            } else {
-                sendMessage(msg);
-            }
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            mCurrentControllerInfo = ((Pair<RemoteUserInfo, Object>) msg.obj).first;
-
-            VolumeProvider vp;
-            Object obj = ((Pair<RemoteUserInfo, Object>) msg.obj).second;
-
-            switch (msg.what) {
-                case MSG_COMMAND:
-                    Command cmd = (Command) obj;
-                    mCallback.onCommand(cmd.command, cmd.extras, cmd.stub);
-                    break;
-                case MSG_MEDIA_BUTTON:
-                    mCallback.onMediaButtonEvent((Intent) obj);
-                    break;
-                case MSG_PREPARE:
-                    mCallback.onPrepare();
-                    break;
-                case MSG_PREPARE_MEDIA_ID:
-                    mCallback.onPrepareFromMediaId((String) obj, msg.getData());
-                    break;
-                case MSG_PREPARE_SEARCH:
-                    mCallback.onPrepareFromSearch((String) obj, msg.getData());
-                    break;
-                case MSG_PREPARE_URI:
-                    mCallback.onPrepareFromUri((Uri) obj, msg.getData());
-                    break;
-                case MSG_PLAY:
-                    mCallback.onPlay();
-                    break;
-                case MSG_PLAY_MEDIA_ID:
-                    mCallback.onPlayFromMediaId((String) obj, msg.getData());
-                    break;
-                case MSG_PLAY_SEARCH:
-                    mCallback.onPlayFromSearch((String) obj, msg.getData());
-                    break;
-                case MSG_PLAY_URI:
-                    mCallback.onPlayFromUri((Uri) obj, msg.getData());
-                    break;
-                case MSG_SKIP_TO_ITEM:
-                    mCallback.onSkipToQueueItem((Long) obj);
-                    break;
-                case MSG_PAUSE:
-                    mCallback.onPause();
-                    break;
-                case MSG_STOP:
-                    mCallback.onStop();
-                    break;
-                case MSG_NEXT:
-                    mCallback.onSkipToNext();
-                    break;
-                case MSG_PREVIOUS:
-                    mCallback.onSkipToPrevious();
-                    break;
-                case MSG_FAST_FORWARD:
-                    mCallback.onFastForward();
-                    break;
-                case MSG_REWIND:
-                    mCallback.onRewind();
-                    break;
-                case MSG_SEEK_TO:
-                    mCallback.onSeekTo((Long) obj);
-                    break;
-                case MSG_RATE:
-                    mCallback.onSetRating((Rating) obj);
-                    break;
-                case MSG_CUSTOM_ACTION:
-                    mCallback.onCustomAction((String) obj, msg.getData());
-                    break;
-                case MSG_ADJUST_VOLUME:
-                    synchronized (mLock) {
-                        vp = mVolumeProvider;
-                    }
-                    if (vp != null) {
-                        vp.onAdjustVolume((int) obj);
-                    }
-                    break;
-                case MSG_SET_VOLUME:
-                    synchronized (mLock) {
-                        vp = mVolumeProvider;
-                    }
-                    if (vp != null) {
-                        vp.onSetVolumeTo((int) obj);
-                    }
-                    break;
-                case MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT:
-                    mCallback.handleMediaPlayPauseKeySingleTapIfPending();
-                    break;
-            }
-            mCurrentControllerInfo = null;
-        }
-    }
-}
diff --git a/packages/MediaComponents/apex/java/android/media/session/ParcelableVolumeInfo.aidl b/packages/MediaComponents/apex/java/android/media/session/ParcelableVolumeInfo.aidl
deleted file mode 100644
index c4250f0..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/ParcelableVolumeInfo.aidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/* Copyright 2014, 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.session;
-
-parcelable ParcelableVolumeInfo;
diff --git a/packages/MediaComponents/apex/java/android/media/session/ParcelableVolumeInfo.java b/packages/MediaComponents/apex/java/android/media/session/ParcelableVolumeInfo.java
deleted file mode 100644
index f59c975..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/ParcelableVolumeInfo.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/* Copyright 2014, 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.session;
-
-import android.media.AudioAttributes;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Convenience class for passing information about the audio configuration of a
- * session. The public implementation is {@link MediaController.PlaybackInfo}.
- *
- * @hide
- */
-public class ParcelableVolumeInfo implements Parcelable {
-    public int volumeType;
-    public AudioAttributes audioAttrs;
-    public int controlType;
-    public int maxVolume;
-    public int currentVolume;
-
-    public ParcelableVolumeInfo(int volumeType, AudioAttributes audioAttrs, int controlType,
-            int maxVolume,
-            int currentVolume) {
-        this.volumeType = volumeType;
-        this.audioAttrs = audioAttrs;
-        this.controlType = controlType;
-        this.maxVolume = maxVolume;
-        this.currentVolume = currentVolume;
-    }
-
-    public ParcelableVolumeInfo(Parcel from) {
-        volumeType = from.readInt();
-        controlType = from.readInt();
-        maxVolume = from.readInt();
-        currentVolume = from.readInt();
-        audioAttrs = AudioAttributes.CREATOR.createFromParcel(from);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(volumeType);
-        dest.writeInt(controlType);
-        dest.writeInt(maxVolume);
-        dest.writeInt(currentVolume);
-        audioAttrs.writeToParcel(dest, flags);
-    }
-
-
-    public static final Parcelable.Creator<ParcelableVolumeInfo> CREATOR
-            = new Parcelable.Creator<ParcelableVolumeInfo>() {
-        @Override
-        public ParcelableVolumeInfo createFromParcel(Parcel in) {
-            return new ParcelableVolumeInfo(in);
-        }
-
-        @Override
-        public ParcelableVolumeInfo[] newArray(int size) {
-            return new ParcelableVolumeInfo[size];
-        }
-    };
-}
diff --git a/packages/MediaComponents/apex/java/android/media/session/PlaybackState.aidl b/packages/MediaComponents/apex/java/android/media/session/PlaybackState.aidl
deleted file mode 100644
index 0876ebd..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/PlaybackState.aidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/* Copyright 2014, 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.session;
-
-parcelable PlaybackState;
diff --git a/packages/MediaComponents/apex/java/android/media/session/PlaybackState.java b/packages/MediaComponents/apex/java/android/media/session/PlaybackState.java
deleted file mode 100644
index ed4f9af..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/PlaybackState.java
+++ /dev/null
@@ -1,1081 +0,0 @@
-/*
- * Copyright (C) 2014 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.session;
-
-import android.annotation.DrawableRes;
-import android.annotation.IntDef;
-import android.annotation.LongDef;
-import android.annotation.Nullable;
-import android.media.RemoteControlClient;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.SystemClock;
-import android.text.TextUtils;
-import java.util.ArrayList;
-import java.util.List;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Playback state for a {@link MediaSession}. This includes a state like
- * {@link PlaybackState#STATE_PLAYING}, the current playback position,
- * and the current control capabilities.
- */
-public final class PlaybackState implements Parcelable {
-    private static final String TAG = "PlaybackState";
-
-    /**
-     * @hide
-     */
-    @LongDef(flag=true, value={ACTION_STOP, ACTION_PAUSE, ACTION_PLAY, ACTION_REWIND,
-            ACTION_SKIP_TO_PREVIOUS, ACTION_SKIP_TO_NEXT, ACTION_FAST_FORWARD, ACTION_SET_RATING,
-            ACTION_SEEK_TO, ACTION_PLAY_PAUSE, ACTION_PLAY_FROM_MEDIA_ID, ACTION_PLAY_FROM_SEARCH,
-            ACTION_SKIP_TO_QUEUE_ITEM, ACTION_PLAY_FROM_URI, ACTION_PREPARE,
-            ACTION_PREPARE_FROM_MEDIA_ID, ACTION_PREPARE_FROM_SEARCH, ACTION_PREPARE_FROM_URI})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface Actions {}
-
-    /**
-     * Indicates this session supports the stop command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_STOP = 1 << 0;
-
-    /**
-     * Indicates this session supports the pause command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_PAUSE = 1 << 1;
-
-    /**
-     * Indicates this session supports the play command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_PLAY = 1 << 2;
-
-    /**
-     * Indicates this session supports the rewind command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_REWIND = 1 << 3;
-
-    /**
-     * Indicates this session supports the previous command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_SKIP_TO_PREVIOUS = 1 << 4;
-
-    /**
-     * Indicates this session supports the next command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_SKIP_TO_NEXT = 1 << 5;
-
-    /**
-     * Indicates this session supports the fast forward command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_FAST_FORWARD = 1 << 6;
-
-    /**
-     * Indicates this session supports the set rating command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_SET_RATING = 1 << 7;
-
-    /**
-     * Indicates this session supports the seek to command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_SEEK_TO = 1 << 8;
-
-    /**
-     * Indicates this session supports the play/pause toggle command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_PLAY_PAUSE = 1 << 9;
-
-    /**
-     * Indicates this session supports the play from media id command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_PLAY_FROM_MEDIA_ID = 1 << 10;
-
-    /**
-     * Indicates this session supports the play from search command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_PLAY_FROM_SEARCH = 1 << 11;
-
-    /**
-     * Indicates this session supports the skip to queue item command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_SKIP_TO_QUEUE_ITEM = 1 << 12;
-
-    /**
-     * Indicates this session supports the play from URI command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_PLAY_FROM_URI = 1 << 13;
-
-    /**
-     * Indicates this session supports the prepare command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_PREPARE = 1 << 14;
-
-    /**
-     * Indicates this session supports the prepare from media id command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_PREPARE_FROM_MEDIA_ID = 1 << 15;
-
-    /**
-     * Indicates this session supports the prepare from search command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_PREPARE_FROM_SEARCH = 1 << 16;
-
-    /**
-     * Indicates this session supports the prepare from URI command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_PREPARE_FROM_URI = 1 << 17;
-
-    /**
-     * @hide
-     */
-    @IntDef({STATE_NONE, STATE_STOPPED, STATE_PAUSED, STATE_PLAYING, STATE_FAST_FORWARDING,
-            STATE_REWINDING, STATE_BUFFERING, STATE_ERROR, STATE_CONNECTING,
-            STATE_SKIPPING_TO_PREVIOUS, STATE_SKIPPING_TO_NEXT, STATE_SKIPPING_TO_QUEUE_ITEM})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface State {}
-
-    /**
-     * This is the default playback state and indicates that no media has been
-     * added yet, or the performer has been reset and has no content to play.
-     *
-     * @see Builder#setState(int, long, float)
-     * @see Builder#setState(int, long, float, long)
-     */
-    public final static int STATE_NONE = 0;
-
-    /**
-     * State indicating this item is currently stopped.
-     *
-     * @see Builder#setState
-     */
-    public final static int STATE_STOPPED = 1;
-
-    /**
-     * State indicating this item is currently paused.
-     *
-     * @see Builder#setState
-     */
-    public final static int STATE_PAUSED = 2;
-
-    /**
-     * State indicating this item is currently playing.
-     *
-     * @see Builder#setState
-     */
-    public final static int STATE_PLAYING = 3;
-
-    /**
-     * State indicating this item is currently fast forwarding.
-     *
-     * @see Builder#setState
-     */
-    public final static int STATE_FAST_FORWARDING = 4;
-
-    /**
-     * State indicating this item is currently rewinding.
-     *
-     * @see Builder#setState
-     */
-    public final static int STATE_REWINDING = 5;
-
-    /**
-     * State indicating this item is currently buffering and will begin playing
-     * when enough data has buffered.
-     *
-     * @see Builder#setState
-     */
-    public final static int STATE_BUFFERING = 6;
-
-    /**
-     * State indicating this item is currently in an error state. The error
-     * message should also be set when entering this state.
-     *
-     * @see Builder#setState
-     */
-    public final static int STATE_ERROR = 7;
-
-    /**
-     * State indicating the class doing playback is currently connecting to a
-     * new destination.  Depending on the implementation you may return to the previous
-     * state when the connection finishes or enter {@link #STATE_NONE}.
-     * If the connection failed {@link #STATE_ERROR} should be used.
-     *
-     * @see Builder#setState
-     */
-    public final static int STATE_CONNECTING = 8;
-
-    /**
-     * State indicating the player is currently skipping to the previous item.
-     *
-     * @see Builder#setState
-     */
-    public final static int STATE_SKIPPING_TO_PREVIOUS = 9;
-
-    /**
-     * State indicating the player is currently skipping to the next item.
-     *
-     * @see Builder#setState
-     */
-    public final static int STATE_SKIPPING_TO_NEXT = 10;
-
-    /**
-     * State indicating the player is currently skipping to a specific item in
-     * the queue.
-     *
-     * @see Builder#setState
-     */
-    public final static int STATE_SKIPPING_TO_QUEUE_ITEM = 11;
-
-    /**
-     * Use this value for the position to indicate the position is not known.
-     */
-    public final static long PLAYBACK_POSITION_UNKNOWN = -1;
-
-    private final int mState;
-    private final long mPosition;
-    private final long mBufferedPosition;
-    private final float mSpeed;
-    private final long mActions;
-    private List<PlaybackState.CustomAction> mCustomActions;
-    private final CharSequence mErrorMessage;
-    private final long mUpdateTime;
-    private final long mActiveItemId;
-    private final Bundle mExtras;
-
-    private PlaybackState(int state, long position, long updateTime, float speed,
-            long bufferedPosition, long transportControls,
-            List<PlaybackState.CustomAction> customActions, long activeItemId,
-            CharSequence error, Bundle extras) {
-        mState = state;
-        mPosition = position;
-        mSpeed = speed;
-        mUpdateTime = updateTime;
-        mBufferedPosition = bufferedPosition;
-        mActions = transportControls;
-        mCustomActions = new ArrayList<>(customActions);
-        mActiveItemId = activeItemId;
-        mErrorMessage = error;
-        mExtras = extras;
-    }
-
-    private PlaybackState(Parcel in) {
-        mState = in.readInt();
-        mPosition = in.readLong();
-        mSpeed = in.readFloat();
-        mUpdateTime = in.readLong();
-        mBufferedPosition = in.readLong();
-        mActions = in.readLong();
-        mCustomActions = in.createTypedArrayList(CustomAction.CREATOR);
-        mActiveItemId = in.readLong();
-        mErrorMessage = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
-        mExtras = in.readBundle();
-    }
-
-    @Override
-    public String toString() {
-        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(", actions=").append(mActions);
-        bob.append(", custom actions=").append(mCustomActions);
-        bob.append(", active item id=").append(mActiveItemId);
-        bob.append(", error=").append(mErrorMessage);
-        bob.append("}");
-        return bob.toString();
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mState);
-        dest.writeLong(mPosition);
-        dest.writeFloat(mSpeed);
-        dest.writeLong(mUpdateTime);
-        dest.writeLong(mBufferedPosition);
-        dest.writeLong(mActions);
-        dest.writeTypedList(mCustomActions);
-        dest.writeLong(mActiveItemId);
-        TextUtils.writeToParcel(mErrorMessage, dest, 0);
-        dest.writeBundle(mExtras);
-    }
-
-    /**
-     * Get the current state of playback. One of the following:
-     * <ul>
-     * <li> {@link PlaybackState#STATE_NONE}</li>
-     * <li> {@link PlaybackState#STATE_STOPPED}</li>
-     * <li> {@link PlaybackState#STATE_PLAYING}</li>
-     * <li> {@link PlaybackState#STATE_PAUSED}</li>
-     * <li> {@link PlaybackState#STATE_FAST_FORWARDING}</li>
-     * <li> {@link PlaybackState#STATE_REWINDING}</li>
-     * <li> {@link PlaybackState#STATE_BUFFERING}</li>
-     * <li> {@link PlaybackState#STATE_ERROR}</li>
-     * <li> {@link PlaybackState#STATE_CONNECTING}</li>
-     * <li> {@link PlaybackState#STATE_SKIPPING_TO_PREVIOUS}</li>
-     * <li> {@link PlaybackState#STATE_SKIPPING_TO_NEXT}</li>
-     * <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
-     * </ul>
-     */
-    @State
-    public int getState() {
-        return mState;
-    }
-
-    /**
-     * Get the current playback position in ms.
-     */
-    public long getPosition() {
-        return mPosition;
-    }
-
-    /**
-     * Get the current buffered position in ms. This is the farthest playback
-     * point that can be reached from the current position using only buffered
-     * content.
-     */
-    public long getBufferedPosition() {
-        return mBufferedPosition;
-    }
-
-    /**
-     * Get the current playback speed as a multiple of normal playback. This
-     * should be negative when rewinding. A value of 1 means normal playback and
-     * 0 means paused.
-     *
-     * @return The current speed of playback.
-     */
-    public float getPlaybackSpeed() {
-        return mSpeed;
-    }
-
-    /**
-     * Get the current actions available on this session. This should use a
-     * bitmask of the available actions.
-     * <ul>
-     * <li> {@link PlaybackState#ACTION_SKIP_TO_PREVIOUS}</li>
-     * <li> {@link PlaybackState#ACTION_REWIND}</li>
-     * <li> {@link PlaybackState#ACTION_PLAY}</li>
-     * <li> {@link PlaybackState#ACTION_PAUSE}</li>
-     * <li> {@link PlaybackState#ACTION_STOP}</li>
-     * <li> {@link PlaybackState#ACTION_FAST_FORWARD}</li>
-     * <li> {@link PlaybackState#ACTION_SKIP_TO_NEXT}</li>
-     * <li> {@link PlaybackState#ACTION_SEEK_TO}</li>
-     * <li> {@link PlaybackState#ACTION_SET_RATING}</li>
-     * <li> {@link PlaybackState#ACTION_PLAY_PAUSE}</li>
-     * <li> {@link PlaybackState#ACTION_PLAY_FROM_MEDIA_ID}</li>
-     * <li> {@link PlaybackState#ACTION_PLAY_FROM_SEARCH}</li>
-     * <li> {@link PlaybackState#ACTION_SKIP_TO_QUEUE_ITEM}</li>
-     * <li> {@link PlaybackState#ACTION_PLAY_FROM_URI}</li>
-     * <li> {@link PlaybackState#ACTION_PREPARE}</li>
-     * <li> {@link PlaybackState#ACTION_PREPARE_FROM_MEDIA_ID}</li>
-     * <li> {@link PlaybackState#ACTION_PREPARE_FROM_SEARCH}</li>
-     * <li> {@link PlaybackState#ACTION_PREPARE_FROM_URI}</li>
-     * </ul>
-     */
-    @Actions
-    public long getActions() {
-        return mActions;
-    }
-
-    /**
-     * Get the list of custom actions.
-     */
-    public List<PlaybackState.CustomAction> getCustomActions() {
-        return mCustomActions;
-    }
-
-    /**
-     * Get a user readable error message. This should be set when the state is
-     * {@link PlaybackState#STATE_ERROR}.
-     */
-    public CharSequence getErrorMessage() {
-        return mErrorMessage;
-    }
-
-    /**
-     * Get the elapsed real time at which position was last updated. If the
-     * position has never been set this will return 0;
-     *
-     * @return The last time the position was updated.
-     */
-    public long getLastPositionUpdateTime() {
-        return mUpdateTime;
-    }
-
-    /**
-     * Get the id of the currently active item in the queue. If there is no
-     * queue or a queue is not supported by the session this will be
-     * {@link MediaSession.QueueItem#UNKNOWN_ID}.
-     *
-     * @return The id of the currently active item in the queue or
-     *         {@link MediaSession.QueueItem#UNKNOWN_ID}.
-     */
-    public long getActiveQueueItemId() {
-        return mActiveItemId;
-    }
-
-    /**
-     * Get any custom extras that were set on this playback state.
-     *
-     * @return The extras for this state or null.
-     */
-    public @Nullable Bundle getExtras() {
-        return mExtras;
-    }
-
-    /**
-     * Get the {@link PlaybackState} state for the given
-     * {@link RemoteControlClient} state.
-     *
-     * @param rccState The state used by {@link RemoteControlClient}.
-     * @return The equivalent state used by {@link PlaybackState}.
-     * @hide
-     */
-    public static int getStateFromRccState(int rccState) {
-        switch (rccState) {
-            case RemoteControlClient.PLAYSTATE_BUFFERING:
-                return STATE_BUFFERING;
-            case RemoteControlClient.PLAYSTATE_ERROR:
-                return STATE_ERROR;
-            case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
-                return STATE_FAST_FORWARDING;
-            //RemoteControlClient.PLAYSTATE_NONE is hidden
-            case 0:  //RemoteControlClient.PLAYSTATE_NONE:
-                return STATE_NONE;
-            case RemoteControlClient.PLAYSTATE_PAUSED:
-                return STATE_PAUSED;
-            case RemoteControlClient.PLAYSTATE_PLAYING:
-                return STATE_PLAYING;
-            case RemoteControlClient.PLAYSTATE_REWINDING:
-                return STATE_REWINDING;
-            case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
-                return STATE_SKIPPING_TO_PREVIOUS;
-            case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
-                return STATE_SKIPPING_TO_NEXT;
-            case RemoteControlClient.PLAYSTATE_STOPPED:
-                return STATE_STOPPED;
-            default:
-                return -1;
-        }
-    }
-
-    /**
-     * Get the {@link RemoteControlClient} state for the given
-     * {@link PlaybackState} state.
-     *
-     * @param state The state used by {@link PlaybackState}.
-     * @return The equivalent state used by {@link RemoteControlClient}.
-     * @hide
-     */
-    public static int getRccStateFromState(int state) {
-        switch (state) {
-            case STATE_BUFFERING:
-                return RemoteControlClient.PLAYSTATE_BUFFERING;
-            case STATE_ERROR:
-                return RemoteControlClient.PLAYSTATE_ERROR;
-            case STATE_FAST_FORWARDING:
-                return RemoteControlClient.PLAYSTATE_FAST_FORWARDING;
-            case STATE_NONE:
-                //RemoteControlClient.PLAYSTATE_NONE is hidden
-                return 0;  //RemoteControlClient.PLAYSTATE_NONE;
-            case STATE_PAUSED:
-                return RemoteControlClient.PLAYSTATE_PAUSED;
-            case STATE_PLAYING:
-                return RemoteControlClient.PLAYSTATE_PLAYING;
-            case STATE_REWINDING:
-                return RemoteControlClient.PLAYSTATE_REWINDING;
-            case STATE_SKIPPING_TO_PREVIOUS:
-                return RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS;
-            case STATE_SKIPPING_TO_NEXT:
-                return RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS;
-            case STATE_STOPPED:
-                return RemoteControlClient.PLAYSTATE_STOPPED;
-            default:
-                return -1;
-        }
-    }
-
-    /**
-     * @hide
-     */
-    public static long getActionsFromRccControlFlags(int rccFlags) {
-        long actions = 0;
-        long flag = 1;
-        while (flag <= rccFlags) {
-            if ((flag & rccFlags) != 0) {
-                actions |= getActionForRccFlag((int) flag);
-            }
-            flag = flag << 1;
-        }
-        return actions;
-    }
-
-    /**
-     * @hide
-     */
-    public static int getRccControlFlagsFromActions(long actions) {
-        int rccFlags = 0;
-        long action = 1;
-        while (action <= actions && action < Integer.MAX_VALUE) {
-            if ((action & actions) != 0) {
-                rccFlags |= getRccFlagForAction(action);
-            }
-            action = action << 1;
-        }
-        return rccFlags;
-    }
-
-    private static long getActionForRccFlag(int flag) {
-        switch (flag) {
-            case RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS:
-                return ACTION_SKIP_TO_PREVIOUS;
-            case RemoteControlClient.FLAG_KEY_MEDIA_REWIND:
-                return ACTION_REWIND;
-            case RemoteControlClient.FLAG_KEY_MEDIA_PLAY:
-                return ACTION_PLAY;
-            case RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE:
-                return ACTION_PLAY_PAUSE;
-            case RemoteControlClient.FLAG_KEY_MEDIA_PAUSE:
-                return ACTION_PAUSE;
-            case RemoteControlClient.FLAG_KEY_MEDIA_STOP:
-                return ACTION_STOP;
-            case RemoteControlClient.FLAG_KEY_MEDIA_FAST_FORWARD:
-                return ACTION_FAST_FORWARD;
-            case RemoteControlClient.FLAG_KEY_MEDIA_NEXT:
-                return ACTION_SKIP_TO_NEXT;
-            case RemoteControlClient.FLAG_KEY_MEDIA_POSITION_UPDATE:
-                return ACTION_SEEK_TO;
-            case RemoteControlClient.FLAG_KEY_MEDIA_RATING:
-                return ACTION_SET_RATING;
-        }
-        return 0;
-    }
-
-    private static int getRccFlagForAction(long action) {
-        // We only care about the lower set of actions that can map to rcc
-        // flags.
-        int testAction = action < Integer.MAX_VALUE ? (int) action : 0;
-        switch (testAction) {
-            case (int) ACTION_SKIP_TO_PREVIOUS:
-                return RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS;
-            case (int) ACTION_REWIND:
-                return RemoteControlClient.FLAG_KEY_MEDIA_REWIND;
-            case (int) ACTION_PLAY:
-                return RemoteControlClient.FLAG_KEY_MEDIA_PLAY;
-            case (int) ACTION_PLAY_PAUSE:
-                return RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE;
-            case (int) ACTION_PAUSE:
-                return RemoteControlClient.FLAG_KEY_MEDIA_PAUSE;
-            case (int) ACTION_STOP:
-                return RemoteControlClient.FLAG_KEY_MEDIA_STOP;
-            case (int) ACTION_FAST_FORWARD:
-                return RemoteControlClient.FLAG_KEY_MEDIA_FAST_FORWARD;
-            case (int) ACTION_SKIP_TO_NEXT:
-                return RemoteControlClient.FLAG_KEY_MEDIA_NEXT;
-            case (int) ACTION_SEEK_TO:
-                return RemoteControlClient.FLAG_KEY_MEDIA_POSITION_UPDATE;
-            case (int) ACTION_SET_RATING:
-                return RemoteControlClient.FLAG_KEY_MEDIA_RATING;
-        }
-        return 0;
-    }
-
-    public static final Parcelable.Creator<PlaybackState> CREATOR =
-            new Parcelable.Creator<PlaybackState>() {
-        @Override
-        public PlaybackState createFromParcel(Parcel in) {
-            return new PlaybackState(in);
-        }
-
-        @Override
-        public PlaybackState[] newArray(int size) {
-            return new PlaybackState[size];
-        }
-    };
-
-    /**
-     * {@link PlaybackState.CustomAction CustomActions} can be used to extend the capabilities of
-     * the standard transport controls by exposing app specific actions to
-     * {@link MediaController MediaControllers}.
-     */
-    public static final class CustomAction implements Parcelable {
-        private final String mAction;
-        private final CharSequence mName;
-        private final int mIcon;
-        private final Bundle mExtras;
-
-        /**
-         * Use {@link PlaybackState.CustomAction.Builder#build()}.
-         */
-        private CustomAction(String action, CharSequence name, int icon, Bundle extras) {
-            mAction = action;
-            mName = name;
-            mIcon = icon;
-            mExtras = extras;
-        }
-
-        private CustomAction(Parcel in) {
-            mAction = in.readString();
-            mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
-            mIcon = in.readInt();
-            mExtras = in.readBundle();
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            dest.writeString(mAction);
-            TextUtils.writeToParcel(mName, dest, flags);
-            dest.writeInt(mIcon);
-            dest.writeBundle(mExtras);
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        public static final Parcelable.Creator<PlaybackState.CustomAction> CREATOR
-                = new Parcelable.Creator<PlaybackState.CustomAction>() {
-
-            @Override
-            public PlaybackState.CustomAction createFromParcel(Parcel p) {
-                return new PlaybackState.CustomAction(p);
-            }
-
-            @Override
-            public PlaybackState.CustomAction[] newArray(int size) {
-                return new PlaybackState.CustomAction[size];
-            }
-        };
-
-        /**
-         * Returns the action of the {@link CustomAction}.
-         *
-         * @return The action of the {@link CustomAction}.
-         */
-        public String getAction() {
-            return mAction;
-        }
-
-        /**
-         * Returns the display name of this action. e.g. "Favorite"
-         *
-         * @return The display name of this {@link CustomAction}.
-         */
-        public CharSequence getName() {
-            return mName;
-        }
-
-        /**
-         * Returns the resource id of the icon in the {@link MediaSession MediaSession's} package.
-         *
-         * @return The resource id of the icon in the {@link MediaSession MediaSession's} package.
-         */
-        public int getIcon() {
-            return mIcon;
-        }
-
-        /**
-         * Returns extras which provide additional application-specific information about the
-         * action, or null if none. These arguments are meant to be consumed by a
-         * {@link MediaController} if it knows how to handle them.
-         *
-         * @return Optional arguments for the {@link CustomAction}.
-         */
-        public Bundle getExtras() {
-            return mExtras;
-        }
-
-        @Override
-        public String toString() {
-            return "Action:" +
-                    "mName='" + mName +
-                    ", mIcon=" + mIcon +
-                    ", mExtras=" + mExtras;
-        }
-
-        /**
-         * Builder for {@link CustomAction} objects.
-         */
-        public static final class Builder {
-            private final String mAction;
-            private final CharSequence mName;
-            private final int mIcon;
-            private Bundle mExtras;
-
-            /**
-             * Creates a {@link CustomAction} builder with the id, name, and icon set.
-             *
-             * @param action The action of the {@link CustomAction}.
-             * @param name The display name of the {@link CustomAction}. This name will be displayed
-             *             along side the action if the UI supports it.
-             * @param icon The icon resource id of the {@link CustomAction}. This resource id
-             *             must be in the same package as the {@link MediaSession}. It will be
-             *             displayed with the custom action if the UI supports it.
-             */
-            public Builder(String action, CharSequence name, @DrawableRes int icon) {
-                if (TextUtils.isEmpty(action)) {
-                    throw new IllegalArgumentException(
-                            "You must specify an action to build a CustomAction.");
-                }
-                if (TextUtils.isEmpty(name)) {
-                    throw new IllegalArgumentException(
-                            "You must specify a name to build a CustomAction.");
-                }
-                if (icon == 0) {
-                    throw new IllegalArgumentException(
-                            "You must specify an icon resource id to build a CustomAction.");
-                }
-                mAction = action;
-                mName = name;
-                mIcon = icon;
-            }
-
-            /**
-             * Set optional extras for the {@link CustomAction}. These extras are meant to be
-             * consumed by a {@link MediaController} if it knows how to handle them.
-             * Keys should be fully qualified (e.g. "com.example.MY_ARG") to avoid collisions.
-             *
-             * @param extras Optional extras for the {@link CustomAction}.
-             * @return this.
-             */
-            public Builder setExtras(Bundle extras) {
-                mExtras = extras;
-                return this;
-            }
-
-            /**
-             * Build and return the {@link CustomAction} instance with the specified values.
-             *
-             * @return A new {@link CustomAction} instance.
-             */
-            public CustomAction build() {
-                return new CustomAction(mAction, mName, mIcon, mExtras);
-            }
-        }
-    }
-
-    /**
-     * Builder for {@link PlaybackState} objects.
-     */
-    public static final class Builder {
-        private final List<PlaybackState.CustomAction> mCustomActions = new ArrayList<>();
-
-        private int mState;
-        private long mPosition;
-        private long mBufferedPosition;
-        private float mSpeed;
-        private long mActions;
-        private CharSequence mErrorMessage;
-        private long mUpdateTime;
-        private long mActiveItemId = MediaSession.QueueItem.UNKNOWN_ID;
-        private Bundle mExtras;
-
-        /**
-         * Creates an initially empty state builder.
-         */
-        public Builder() {
-        }
-
-        /**
-         * Creates a builder with the same initial values as those in the from
-         * state.
-         *
-         * @param from The state to use for initializing the builder.
-         */
-        public Builder(PlaybackState from) {
-            if (from == null) {
-                return;
-            }
-            mState = from.mState;
-            mPosition = from.mPosition;
-            mBufferedPosition = from.mBufferedPosition;
-            mSpeed = from.mSpeed;
-            mActions = from.mActions;
-            if (from.mCustomActions != null) {
-                mCustomActions.addAll(from.mCustomActions);
-            }
-            mErrorMessage = from.mErrorMessage;
-            mUpdateTime = from.mUpdateTime;
-            mActiveItemId = from.mActiveItemId;
-            mExtras = from.mExtras;
-        }
-
-        /**
-         * Set the current state of playback.
-         * <p>
-         * The position must be in ms and indicates the current playback
-         * position within the item. If the position is unknown use
-         * {@link #PLAYBACK_POSITION_UNKNOWN}. When not using an unknown
-         * position the time at which the position was updated must be provided.
-         * It is okay to use {@link SystemClock#elapsedRealtime()} if the
-         * current position was just retrieved.
-         * <p>
-         * The speed is a multiple of normal playback and should be 0 when
-         * paused and negative when rewinding. Normal playback speed is 1.0.
-         * <p>
-         * The state must be one of the following:
-         * <ul>
-         * <li> {@link PlaybackState#STATE_NONE}</li>
-         * <li> {@link PlaybackState#STATE_STOPPED}</li>
-         * <li> {@link PlaybackState#STATE_PLAYING}</li>
-         * <li> {@link PlaybackState#STATE_PAUSED}</li>
-         * <li> {@link PlaybackState#STATE_FAST_FORWARDING}</li>
-         * <li> {@link PlaybackState#STATE_REWINDING}</li>
-         * <li> {@link PlaybackState#STATE_BUFFERING}</li>
-         * <li> {@link PlaybackState#STATE_ERROR}</li>
-         * <li> {@link PlaybackState#STATE_CONNECTING}</li>
-         * <li> {@link PlaybackState#STATE_SKIPPING_TO_PREVIOUS}</li>
-         * <li> {@link PlaybackState#STATE_SKIPPING_TO_NEXT}</li>
-         * <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
-         * </ul>
-         *
-         * @param state The current state of playback.
-         * @param position The position in the current item in ms.
-         * @param playbackSpeed The current speed of playback as a multiple of
-         *            normal playback.
-         * @param updateTime The time in the {@link SystemClock#elapsedRealtime}
-         *            timebase that the position was updated at.
-         * @return this
-         */
-        public Builder setState(@State int state, long position, float playbackSpeed,
-                long updateTime) {
-            mState = state;
-            mPosition = position;
-            mUpdateTime = updateTime;
-            mSpeed = playbackSpeed;
-            return this;
-        }
-
-        /**
-         * Set the current state of playback.
-         * <p>
-         * The position must be in ms and indicates the current playback
-         * position within the item. If the position is unknown use
-         * {@link #PLAYBACK_POSITION_UNKNOWN}. The update time will be set to
-         * the current {@link SystemClock#elapsedRealtime()}.
-         * <p>
-         * The speed is a multiple of normal playback and should be 0 when
-         * paused and negative when rewinding. Normal playback speed is 1.0.
-         * <p>
-         * The state must be one of the following:
-         * <ul>
-         * <li> {@link PlaybackState#STATE_NONE}</li>
-         * <li> {@link PlaybackState#STATE_STOPPED}</li>
-         * <li> {@link PlaybackState#STATE_PLAYING}</li>
-         * <li> {@link PlaybackState#STATE_PAUSED}</li>
-         * <li> {@link PlaybackState#STATE_FAST_FORWARDING}</li>
-         * <li> {@link PlaybackState#STATE_REWINDING}</li>
-         * <li> {@link PlaybackState#STATE_BUFFERING}</li>
-         * <li> {@link PlaybackState#STATE_ERROR}</li>
-         * <li> {@link PlaybackState#STATE_CONNECTING}</li>
-         * <li> {@link PlaybackState#STATE_SKIPPING_TO_PREVIOUS}</li>
-         * <li> {@link PlaybackState#STATE_SKIPPING_TO_NEXT}</li>
-         * <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
-         * </ul>
-         *
-         * @param state The current state of playback.
-         * @param position The position in the current item in ms.
-         * @param playbackSpeed The current speed of playback as a multiple of
-         *            normal playback.
-         * @return this
-         */
-        public Builder setState(@State int state, long position, float playbackSpeed) {
-            return setState(state, position, playbackSpeed, SystemClock.elapsedRealtime());
-        }
-
-        /**
-         * Set the current actions available on this session. This should use a
-         * bitmask of possible actions.
-         * <ul>
-         * <li> {@link PlaybackState#ACTION_SKIP_TO_PREVIOUS}</li>
-         * <li> {@link PlaybackState#ACTION_REWIND}</li>
-         * <li> {@link PlaybackState#ACTION_PLAY}</li>
-         * <li> {@link PlaybackState#ACTION_PAUSE}</li>
-         * <li> {@link PlaybackState#ACTION_STOP}</li>
-         * <li> {@link PlaybackState#ACTION_FAST_FORWARD}</li>
-         * <li> {@link PlaybackState#ACTION_SKIP_TO_NEXT}</li>
-         * <li> {@link PlaybackState#ACTION_SEEK_TO}</li>
-         * <li> {@link PlaybackState#ACTION_SET_RATING}</li>
-         * <li> {@link PlaybackState#ACTION_PLAY_PAUSE}</li>
-         * <li> {@link PlaybackState#ACTION_PLAY_FROM_MEDIA_ID}</li>
-         * <li> {@link PlaybackState#ACTION_PLAY_FROM_SEARCH}</li>
-         * <li> {@link PlaybackState#ACTION_SKIP_TO_QUEUE_ITEM}</li>
-         * <li> {@link PlaybackState#ACTION_PLAY_FROM_URI}</li>
-         * <li> {@link PlaybackState#ACTION_PREPARE}</li>
-         * <li> {@link PlaybackState#ACTION_PREPARE_FROM_MEDIA_ID}</li>
-         * <li> {@link PlaybackState#ACTION_PREPARE_FROM_SEARCH}</li>
-         * <li> {@link PlaybackState#ACTION_PREPARE_FROM_URI}</li>
-         * </ul>
-         *
-         * @param actions The set of actions allowed.
-         * @return this
-         */
-        public Builder setActions(@Actions long actions) {
-            mActions = actions;
-            return this;
-        }
-
-        /**
-         * Add a custom action to the playback state. Actions can be used to
-         * expose additional functionality to {@link MediaController
-         * MediaControllers} beyond what is offered by the standard transport
-         * controls.
-         * <p>
-         * e.g. start a radio station based on the current item or skip ahead by
-         * 30 seconds.
-         *
-         * @param action An identifier for this action. It can be sent back to
-         *            the {@link MediaSession} through
-         *            {@link MediaController.TransportControls#sendCustomAction(String, Bundle)}.
-         * @param name The display name for the action. If text is shown with
-         *            the action or used for accessibility, this is what should
-         *            be used.
-         * @param icon The resource action of the icon that should be displayed
-         *            for the action. The resource should be in the package of
-         *            the {@link MediaSession}.
-         * @return this
-         */
-        public Builder addCustomAction(String action, String name, int icon) {
-            return addCustomAction(new PlaybackState.CustomAction(action, name, icon, null));
-        }
-
-        /**
-         * Add a custom action to the playback state. Actions can be used to expose additional
-         * functionality to {@link MediaController MediaControllers} beyond what is offered by the
-         * standard transport controls.
-         * <p>
-         * An example of an action would be to start a radio station based on the current item
-         * or to skip ahead by 30 seconds.
-         *
-         * @param customAction The custom action to add to the {@link PlaybackState}.
-         * @return this
-         */
-        public Builder addCustomAction(PlaybackState.CustomAction customAction) {
-            if (customAction == null) {
-                throw new IllegalArgumentException(
-                        "You may not add a null CustomAction to PlaybackState.");
-            }
-            mCustomActions.add(customAction);
-            return this;
-        }
-
-        /**
-         * Set the current buffered position in ms. This is the farthest
-         * playback point that can be reached from the current position using
-         * only buffered content.
-         *
-         * @param bufferedPosition The position in ms that playback is buffered
-         *            to.
-         * @return this
-         */
-        public Builder setBufferedPosition(long bufferedPosition) {
-            mBufferedPosition = bufferedPosition;
-            return this;
-        }
-
-        /**
-         * Set the active item in the play queue by specifying its id. The
-         * default value is {@link MediaSession.QueueItem#UNKNOWN_ID}
-         *
-         * @param id The id of the active item.
-         * @return this
-         */
-        public Builder setActiveQueueItemId(long id) {
-            mActiveItemId = id;
-            return this;
-        }
-
-        /**
-         * Set a user readable error message. This should be set when the state
-         * is {@link PlaybackState#STATE_ERROR}.
-         *
-         * @param error The error message for display to the user.
-         * @return this
-         */
-        public Builder setErrorMessage(CharSequence error) {
-            mErrorMessage = error;
-            return this;
-        }
-
-        /**
-         * Set any custom extras to be included with the playback state.
-         *
-         * @param extras The extras to include.
-         * @return this
-         */
-        public Builder setExtras(Bundle extras) {
-            mExtras = extras;
-            return this;
-        }
-
-        /**
-         * Build and return the {@link PlaybackState} instance with these
-         * values.
-         *
-         * @return A new state instance.
-         */
-        public PlaybackState build() {
-            return new PlaybackState(mState, mPosition, mUpdateTime, mSpeed, mBufferedPosition,
-                    mActions, mCustomActions, mActiveItemId, mErrorMessage, mExtras);
-        }
-    }
-}
diff --git a/packages/MediaComponents/apex/java/android/service/media/IMediaBrowserService.aidl b/packages/MediaComponents/apex/java/android/service/media/IMediaBrowserService.aidl
deleted file mode 100644
index 84f41f6..0000000
--- a/packages/MediaComponents/apex/java/android/service/media/IMediaBrowserService.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2014 Google Inc. All Rights Reserved.
-
-package android.service.media;
-
-import android.content.res.Configuration;
-import android.service.media.IMediaBrowserServiceCallbacks;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.ResultReceiver;
-
-/**
- * Media API allows clients to browse through hierarchy of a user’s media collection,
- * playback a specific media entry and interact with the now playing queue.
- * @hide
- */
-oneway interface IMediaBrowserService {
-    void connect(String pkg, in Bundle rootHints, IMediaBrowserServiceCallbacks callbacks);
-    void disconnect(IMediaBrowserServiceCallbacks callbacks);
-
-    void addSubscriptionDeprecated(String uri, IMediaBrowserServiceCallbacks callbacks);
-    void removeSubscriptionDeprecated(String uri, IMediaBrowserServiceCallbacks callbacks);
-
-    void getMediaItem(String uri, in ResultReceiver cb, IMediaBrowserServiceCallbacks callbacks);
-    void addSubscription(String uri, in IBinder token, in Bundle options,
-            IMediaBrowserServiceCallbacks callbacks);
-    void removeSubscription(String uri, in IBinder token, IMediaBrowserServiceCallbacks callbacks);
-}
diff --git a/packages/MediaComponents/apex/java/android/service/media/IMediaBrowserServiceCallbacks.aidl b/packages/MediaComponents/apex/java/android/service/media/IMediaBrowserServiceCallbacks.aidl
deleted file mode 100644
index 8dc480d..0000000
--- a/packages/MediaComponents/apex/java/android/service/media/IMediaBrowserServiceCallbacks.aidl
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2014 Google Inc. All Rights Reserved.
-
-package android.service.media;
-
-import android.graphics.Bitmap;
-import android.media.MediaParceledListSlice;
-import android.media.session.MediaSession;
-import android.os.Bundle;
-
-/**
- * Media API allows clients to browse through hierarchy of a user’s media collection,
- * playback a specific media entry and interact with the now playing queue.
- * @hide
- */
-oneway interface IMediaBrowserServiceCallbacks {
-    /**
-     * Invoked when the connected has been established.
-     * @param root The root media id for browsing.
-     * @param session The {@link MediaSession.Token media session token} that can be used to control
-     *         the playback of the media app.
-     * @param extra Extras returned by the media service.
-     */
-    void onConnect(String root, in MediaSession.Token session, in Bundle extras);
-    void onConnectFailed();
-    void onLoadChildren(String mediaId, in MediaParceledListSlice list);
-    void onLoadChildrenWithOptions(String mediaId, in MediaParceledListSlice list,
-            in Bundle options);
-}
diff --git a/packages/MediaComponents/apex/java/android/service/media/MediaBrowserService.java b/packages/MediaComponents/apex/java/android/service/media/MediaBrowserService.java
deleted file mode 100644
index 76c99b9..0000000
--- a/packages/MediaComponents/apex/java/android/service/media/MediaBrowserService.java
+++ /dev/null
@@ -1,856 +0,0 @@
-/*
- * Copyright (C) 2014 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.service.media;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.UnsupportedAppUsage;
-import android.app.Service;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.media.MediaParceledListSlice;
-import android.media.browse.MediaBrowser;
-import android.media.browse.MediaBrowserUtils;
-import android.media.session.MediaSession;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.media.session.MediaSessionManager;
-import android.media.session.MediaSessionManager.RemoteUserInfo;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.service.media.IMediaBrowserService;
-import android.service.media.IMediaBrowserServiceCallbacks;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.Log;
-import android.util.Pair;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * Base class for media browser services.
- * <p>
- * Media browser services enable applications to browse media content provided by an application
- * and ask the application to start playing it. They may also be used to control content that
- * is already playing by way of a {@link MediaSession}.
- * </p>
- *
- * To extend this class, you must declare the service in your manifest file with
- * an intent filter with the {@link #SERVICE_INTERFACE} action.
- *
- * For example:
- * </p><pre>
- * &lt;service android:name=".MyMediaBrowserService"
- *          android:label="&#64;string/service_name" >
- *     &lt;intent-filter>
- *         &lt;action android:name="android.media.browse.MediaBrowserService" />
- *     &lt;/intent-filter>
- * &lt;/service>
- * </pre>
- *
- */
-public abstract class MediaBrowserService extends Service {
-    private static final String TAG = "MediaBrowserService";
-    private static final boolean DBG = false;
-
-    /**
-     * The {@link Intent} that must be declared as handled by the service.
-     */
-    @SdkConstant(SdkConstantType.SERVICE_ACTION)
-    public static final String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
-
-    /**
-     * A key for passing the MediaItem to the ResultReceiver in getItem.
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public static final String KEY_MEDIA_ITEM = "media_item";
-
-    private static final int RESULT_FLAG_OPTION_NOT_HANDLED = 1 << 0;
-    private static final int RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED = 1 << 1;
-
-    private static final int RESULT_ERROR = -1;
-    private static final int RESULT_OK = 0;
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag=true, value = { RESULT_FLAG_OPTION_NOT_HANDLED,
-            RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED })
-    private @interface ResultFlags { }
-
-    private final ArrayMap<IBinder, ConnectionRecord> mConnections = new ArrayMap<>();
-    private ConnectionRecord mCurConnection;
-    private final Handler mHandler = new Handler();
-    private ServiceBinder mBinder;
-    MediaSession.Token mSession;
-
-    /**
-     * All the info about a connection.
-     */
-    private class ConnectionRecord implements IBinder.DeathRecipient {
-        String pkg;
-        int uid;
-        int pid;
-        Bundle rootHints;
-        IMediaBrowserServiceCallbacks callbacks;
-        BrowserRoot root;
-        HashMap<String, List<Pair<IBinder, Bundle>>> subscriptions = new HashMap<>();
-
-        @Override
-        public void binderDied() {
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    mConnections.remove(callbacks.asBinder());
-                }
-            });
-        }
-    }
-
-    /**
-     * Completion handler for asynchronous callback methods in {@link MediaBrowserService}.
-     * <p>
-     * Each of the methods that takes one of these to send the result must call
-     * {@link #sendResult} to respond to the caller with the given results. If those
-     * functions return without calling {@link #sendResult}, they must instead call
-     * {@link #detach} before returning, and then may call {@link #sendResult} when
-     * they are done. If more than one of those methods is called, an exception will
-     * be thrown.
-     *
-     * @see #onLoadChildren
-     * @see #onLoadItem
-     */
-    public class Result<T> {
-        private Object mDebug;
-        private boolean mDetachCalled;
-        private boolean mSendResultCalled;
-        @UnsupportedAppUsage
-        private int mFlags;
-
-        Result(Object debug) {
-            mDebug = debug;
-        }
-
-        /**
-         * Send the result back to the caller.
-         */
-        public void sendResult(T result) {
-            if (mSendResultCalled) {
-                throw new IllegalStateException("sendResult() called twice for: " + mDebug);
-            }
-            mSendResultCalled = true;
-            onResultSent(result, mFlags);
-        }
-
-        /**
-         * Detach this message from the current thread and allow the {@link #sendResult}
-         * call to happen later.
-         */
-        public void detach() {
-            if (mDetachCalled) {
-                throw new IllegalStateException("detach() called when detach() had already"
-                        + " been called for: " + mDebug);
-            }
-            if (mSendResultCalled) {
-                throw new IllegalStateException("detach() called when sendResult() had already"
-                        + " been called for: " + mDebug);
-            }
-            mDetachCalled = true;
-        }
-
-        boolean isDone() {
-            return mDetachCalled || mSendResultCalled;
-        }
-
-        void setFlags(@ResultFlags int flags) {
-            mFlags = flags;
-        }
-
-        /**
-         * Called when the result is sent, after assertions about not being called twice
-         * have happened.
-         */
-        void onResultSent(T result, @ResultFlags int flags) {
-        }
-    }
-
-    private class ServiceBinder extends IMediaBrowserService.Stub {
-        @Override
-        public void connect(final String pkg, final Bundle rootHints,
-                final IMediaBrowserServiceCallbacks callbacks) {
-
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            if (!isValidPackage(pkg, uid)) {
-                throw new IllegalArgumentException("Package/uid mismatch: uid=" + uid
-                        + " package=" + pkg);
-            }
-
-            mHandler.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        final IBinder b = callbacks.asBinder();
-
-                        // Clear out the old subscriptions. We are getting new ones.
-                        mConnections.remove(b);
-
-                        final ConnectionRecord connection = new ConnectionRecord();
-                        connection.pkg = pkg;
-                        connection.pid = pid;
-                        connection.uid = uid;
-                        connection.rootHints = rootHints;
-                        connection.callbacks = callbacks;
-
-                        mCurConnection = connection;
-                        connection.root = MediaBrowserService.this.onGetRoot(pkg, uid, rootHints);
-                        mCurConnection = null;
-
-                        // If they didn't return something, don't allow this client.
-                        if (connection.root == null) {
-                            Log.i(TAG, "No root for client " + pkg + " from service "
-                                    + getClass().getName());
-                            try {
-                                callbacks.onConnectFailed();
-                            } catch (RemoteException ex) {
-                                Log.w(TAG, "Calling onConnectFailed() failed. Ignoring. "
-                                        + "pkg=" + pkg);
-                            }
-                        } else {
-                            try {
-                                mConnections.put(b, connection);
-                                b.linkToDeath(connection, 0);
-                                if (mSession != null) {
-                                    callbacks.onConnect(connection.root.getRootId(),
-                                            mSession, connection.root.getExtras());
-                                }
-                            } catch (RemoteException ex) {
-                                Log.w(TAG, "Calling onConnect() failed. Dropping client. "
-                                        + "pkg=" + pkg);
-                                mConnections.remove(b);
-                            }
-                        }
-                    }
-                });
-        }
-
-        @Override
-        public void disconnect(final IMediaBrowserServiceCallbacks callbacks) {
-            mHandler.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        final IBinder b = callbacks.asBinder();
-
-                        // Clear out the old subscriptions. We are getting new ones.
-                        final ConnectionRecord old = mConnections.remove(b);
-                        if (old != null) {
-                            // TODO
-                            old.callbacks.asBinder().unlinkToDeath(old, 0);
-                        }
-                    }
-                });
-        }
-
-        @Override
-        public void addSubscriptionDeprecated(String id, IMediaBrowserServiceCallbacks callbacks) {
-            // do-nothing
-        }
-
-        @Override
-        public void addSubscription(final String id, final IBinder token, final Bundle options,
-                final IMediaBrowserServiceCallbacks callbacks) {
-            mHandler.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        final IBinder b = callbacks.asBinder();
-
-                        // Get the record for the connection
-                        final ConnectionRecord connection = mConnections.get(b);
-                        if (connection == null) {
-                            Log.w(TAG, "addSubscription for callback that isn't registered id="
-                                + id);
-                            return;
-                        }
-
-                        MediaBrowserService.this.addSubscription(id, connection, token, options);
-                    }
-                });
-        }
-
-        @Override
-        public void removeSubscriptionDeprecated(String id, IMediaBrowserServiceCallbacks callbacks) {
-            // do-nothing
-        }
-
-        @Override
-        public void removeSubscription(final String id, final IBinder token,
-                final IMediaBrowserServiceCallbacks callbacks) {
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    final IBinder b = callbacks.asBinder();
-
-                    ConnectionRecord connection = mConnections.get(b);
-                    if (connection == null) {
-                        Log.w(TAG, "removeSubscription for callback that isn't registered id="
-                                + id);
-                        return;
-                    }
-                    if (!MediaBrowserService.this.removeSubscription(id, connection, token)) {
-                        Log.w(TAG, "removeSubscription called for " + id
-                                + " which is not subscribed");
-                    }
-                }
-            });
-        }
-
-        @Override
-        public void getMediaItem(final String mediaId, final ResultReceiver receiver,
-                final IMediaBrowserServiceCallbacks callbacks) {
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    final IBinder b = callbacks.asBinder();
-                    ConnectionRecord connection = mConnections.get(b);
-                    if (connection == null) {
-                        Log.w(TAG, "getMediaItem for callback that isn't registered id=" + mediaId);
-                        return;
-                    }
-                    performLoadItem(mediaId, connection, receiver);
-                }
-            });
-        }
-    }
-
-    @Override
-    public void onCreate() {
-        super.onCreate();
-        mBinder = new ServiceBinder();
-    }
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        if (SERVICE_INTERFACE.equals(intent.getAction())) {
-            return mBinder;
-        }
-        return null;
-    }
-
-    @Override
-    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
-    }
-
-    /**
-     * Called to get the root information for browsing by a particular client.
-     * <p>
-     * The implementation should verify that the client package has permission
-     * to access browse media information before returning the root id; it
-     * should return null if the client is not allowed to access this
-     * information.
-     * </p>
-     *
-     * @param clientPackageName The package name of the application which is
-     *            requesting access to browse media.
-     * @param clientUid The uid of the application which is requesting access to
-     *            browse media.
-     * @param rootHints An optional bundle of service-specific arguments to send
-     *            to the media browser service when connecting and retrieving the
-     *            root id for browsing, or null if none. The contents of this
-     *            bundle may affect the information returned when browsing.
-     * @return The {@link BrowserRoot} for accessing this app's content or null.
-     * @see BrowserRoot#EXTRA_RECENT
-     * @see BrowserRoot#EXTRA_OFFLINE
-     * @see BrowserRoot#EXTRA_SUGGESTED
-     */
-    public abstract @Nullable BrowserRoot onGetRoot(@NonNull String clientPackageName,
-            int clientUid, @Nullable Bundle rootHints);
-
-    /**
-     * Called to get information about the children of a media item.
-     * <p>
-     * Implementations must call {@link Result#sendResult result.sendResult}
-     * with the list of children. If loading the children will be an expensive
-     * operation that should be performed on another thread,
-     * {@link Result#detach result.detach} may be called before returning from
-     * this function, and then {@link Result#sendResult result.sendResult}
-     * called when the loading is complete.
-     * </p><p>
-     * In case the media item does not have any children, call {@link Result#sendResult}
-     * with an empty list. When the given {@code parentId} is invalid, implementations must
-     * call {@link Result#sendResult result.sendResult} with {@code null}, which will invoke
-     * {@link MediaBrowser.SubscriptionCallback#onError}.
-     * </p>
-     *
-     * @param parentId The id of the parent media item whose children are to be
-     *            queried.
-     * @param result The Result to send the list of children to.
-     */
-    public abstract void onLoadChildren(@NonNull String parentId,
-            @NonNull Result<List<MediaBrowser.MediaItem>> result);
-
-    /**
-     * Called to get information about the children of a media item.
-     * <p>
-     * Implementations must call {@link Result#sendResult result.sendResult}
-     * with the list of children. If loading the children will be an expensive
-     * operation that should be performed on another thread,
-     * {@link Result#detach result.detach} may be called before returning from
-     * this function, and then {@link Result#sendResult result.sendResult}
-     * called when the loading is complete.
-     * </p><p>
-     * In case the media item does not have any children, call {@link Result#sendResult}
-     * with an empty list. When the given {@code parentId} is invalid, implementations must
-     * call {@link Result#sendResult result.sendResult} with {@code null}, which will invoke
-     * {@link MediaBrowser.SubscriptionCallback#onError}.
-     * </p>
-     *
-     * @param parentId The id of the parent media item whose children are to be
-     *            queried.
-     * @param result The Result to send the list of children to.
-     * @param options The bundle of service-specific arguments sent from the media
-     *            browser. The information returned through the result should be
-     *            affected by the contents of this bundle.
-     */
-    public void onLoadChildren(@NonNull String parentId,
-            @NonNull Result<List<MediaBrowser.MediaItem>> result, @NonNull Bundle options) {
-        // To support backward compatibility, when the implementation of MediaBrowserService doesn't
-        // override onLoadChildren() with options, onLoadChildren() without options will be used
-        // instead, and the options will be applied in the implementation of result.onResultSent().
-        result.setFlags(RESULT_FLAG_OPTION_NOT_HANDLED);
-        onLoadChildren(parentId, result);
-    }
-
-    /**
-     * Called to get information about a specific media item.
-     * <p>
-     * Implementations must call {@link Result#sendResult result.sendResult}. If
-     * loading the item will be an expensive operation {@link Result#detach
-     * result.detach} may be called before returning from this function, and
-     * then {@link Result#sendResult result.sendResult} called when the item has
-     * been loaded.
-     * </p><p>
-     * When the given {@code itemId} is invalid, implementations must call
-     * {@link Result#sendResult result.sendResult} with {@code null}.
-     * </p><p>
-     * The default implementation will invoke {@link MediaBrowser.ItemCallback#onError}.
-     * </p>
-     *
-     * @param itemId The id for the specific
-     *            {@link android.media.browse.MediaBrowser.MediaItem}.
-     * @param result The Result to send the item to.
-     */
-    public void onLoadItem(String itemId, Result<MediaBrowser.MediaItem> result) {
-        result.setFlags(RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED);
-        result.sendResult(null);
-    }
-
-    /**
-     * Call to set the media session.
-     * <p>
-     * This should be called as soon as possible during the service's startup.
-     * It may only be called once.
-     *
-     * @param token The token for the service's {@link MediaSession}.
-     */
-    public void setSessionToken(final MediaSession.Token token) {
-        if (token == null) {
-            throw new IllegalArgumentException("Session token may not be null.");
-        }
-        if (mSession != null) {
-            throw new IllegalStateException("The session token has already been set.");
-        }
-        mSession = token;
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                Iterator<ConnectionRecord> iter = mConnections.values().iterator();
-                while (iter.hasNext()){
-                    ConnectionRecord connection = iter.next();
-                    try {
-                        connection.callbacks.onConnect(connection.root.getRootId(), token,
-                                connection.root.getExtras());
-                    } catch (RemoteException e) {
-                        Log.w(TAG, "Connection for " + connection.pkg + " is no longer valid.");
-                        iter.remove();
-                    }
-                }
-            }
-        });
-    }
-
-    /**
-     * Gets the session token, or null if it has not yet been created
-     * or if it has been destroyed.
-     */
-    public @Nullable MediaSession.Token getSessionToken() {
-        return mSession;
-    }
-
-    /**
-     * Gets the root hints sent from the currently connected {@link MediaBrowser}.
-     * The root hints are service-specific arguments included in an optional bundle sent to the
-     * media browser service when connecting and retrieving the root id for browsing, or null if
-     * none. The contents of this bundle may affect the information returned when browsing.
-     *
-     * @throws IllegalStateException If this method is called outside of {@link #onGetRoot} or
-     *             {@link #onLoadChildren} or {@link #onLoadItem}.
-     * @see MediaBrowserService.BrowserRoot#EXTRA_RECENT
-     * @see MediaBrowserService.BrowserRoot#EXTRA_OFFLINE
-     * @see MediaBrowserService.BrowserRoot#EXTRA_SUGGESTED
-     */
-    public final Bundle getBrowserRootHints() {
-        if (mCurConnection == null) {
-            throw new IllegalStateException("This should be called inside of onGetRoot or"
-                    + " onLoadChildren or onLoadItem methods");
-        }
-        return mCurConnection.rootHints == null ? null : new Bundle(mCurConnection.rootHints);
-    }
-
-    /**
-     * Gets the browser information who sent the current request.
-     *
-     * @throws IllegalStateException If this method is called outside of {@link #onGetRoot} or
-     *             {@link #onLoadChildren} or {@link #onLoadItem}.
-     * @see MediaSessionManager#isTrustedForMediaControl(RemoteUserInfo)
-     */
-    public final RemoteUserInfo getCurrentBrowserInfo() {
-        if (mCurConnection == null) {
-            throw new IllegalStateException("This should be called inside of onGetRoot or"
-                    + " onLoadChildren or onLoadItem methods");
-        }
-        return new RemoteUserInfo(mCurConnection.pkg, mCurConnection.pid, mCurConnection.uid);
-    }
-
-    /**
-     * Notifies all connected media browsers that the children of
-     * the specified parent id have changed in some way.
-     * This will cause browsers to fetch subscribed content again.
-     *
-     * @param parentId The id of the parent media item whose
-     * children changed.
-     */
-    public void notifyChildrenChanged(@NonNull String parentId) {
-        notifyChildrenChangedInternal(parentId, null);
-    }
-
-    /**
-     * Notifies all connected media browsers that the children of
-     * the specified parent id have changed in some way.
-     * This will cause browsers to fetch subscribed content again.
-     *
-     * @param parentId The id of the parent media item whose
-     *            children changed.
-     * @param options The bundle of service-specific arguments to send
-     *            to the media browser. The contents of this bundle may
-     *            contain the information about the change.
-     */
-    public void notifyChildrenChanged(@NonNull String parentId, @NonNull Bundle options) {
-        if (options == null) {
-            throw new IllegalArgumentException("options cannot be null in notifyChildrenChanged");
-        }
-        notifyChildrenChangedInternal(parentId, options);
-    }
-
-    private void notifyChildrenChangedInternal(final String parentId, final Bundle options) {
-        if (parentId == null) {
-            throw new IllegalArgumentException("parentId cannot be null in notifyChildrenChanged");
-        }
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                for (IBinder binder : mConnections.keySet()) {
-                    ConnectionRecord connection = mConnections.get(binder);
-                    List<Pair<IBinder, Bundle>> callbackList =
-                            connection.subscriptions.get(parentId);
-                    if (callbackList != null) {
-                        for (Pair<IBinder, Bundle> callback : callbackList) {
-                            if (MediaBrowserUtils.hasDuplicatedItems(options, callback.second)) {
-                                performLoadChildren(parentId, connection, callback.second);
-                            }
-                        }
-                    }
-                }
-            }
-        });
-    }
-
-    /**
-     * Return whether the given package is one of the ones that is owned by the uid.
-     */
-    private boolean isValidPackage(String pkg, int uid) {
-        if (pkg == null) {
-            return false;
-        }
-        final PackageManager pm = getPackageManager();
-        final String[] packages = pm.getPackagesForUid(uid);
-        final int N = packages.length;
-        for (int i=0; i<N; i++) {
-            if (packages[i].equals(pkg)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Save the subscription and if it is a new subscription send the results.
-     */
-    private void addSubscription(String id, ConnectionRecord connection, IBinder token,
-            Bundle options) {
-        // Save the subscription
-        List<Pair<IBinder, Bundle>> callbackList = connection.subscriptions.get(id);
-        if (callbackList == null) {
-            callbackList = new ArrayList<>();
-        }
-        for (Pair<IBinder, Bundle> callback : callbackList) {
-            if (token == callback.first
-                    && MediaBrowserUtils.areSameOptions(options, callback.second)) {
-                return;
-            }
-        }
-        callbackList.add(new Pair<>(token, options));
-        connection.subscriptions.put(id, callbackList);
-        // send the results
-        performLoadChildren(id, connection, options);
-    }
-
-    /**
-     * Remove the subscription.
-     */
-    private boolean removeSubscription(String id, ConnectionRecord connection, IBinder token) {
-        if (token == null) {
-            return connection.subscriptions.remove(id) != null;
-        }
-        boolean removed = false;
-        List<Pair<IBinder, Bundle>> callbackList = connection.subscriptions.get(id);
-        if (callbackList != null) {
-            Iterator<Pair<IBinder, Bundle>> iter = callbackList.iterator();
-            while (iter.hasNext()){
-                if (token == iter.next().first) {
-                    removed = true;
-                    iter.remove();
-                }
-            }
-            if (callbackList.size() == 0) {
-                connection.subscriptions.remove(id);
-            }
-        }
-        return removed;
-    }
-
-    /**
-     * Call onLoadChildren and then send the results back to the connection.
-     * <p>
-     * Callers must make sure that this connection is still connected.
-     */
-    private void performLoadChildren(final String parentId, final ConnectionRecord connection,
-            final Bundle options) {
-        final Result<List<MediaBrowser.MediaItem>> result
-                = new Result<List<MediaBrowser.MediaItem>>(parentId) {
-            @Override
-            void onResultSent(List<MediaBrowser.MediaItem> list, @ResultFlags int flag) {
-                if (mConnections.get(connection.callbacks.asBinder()) != connection) {
-                    if (DBG) {
-                        Log.d(TAG, "Not sending onLoadChildren result for connection that has"
-                                + " been disconnected. pkg=" + connection.pkg + " id=" + parentId);
-                    }
-                    return;
-                }
-
-                List<MediaBrowser.MediaItem> filteredList =
-                        (flag & RESULT_FLAG_OPTION_NOT_HANDLED) != 0
-                        ? applyOptions(list, options) : list;
-                final MediaParceledListSlice<MediaBrowser.MediaItem> pls =
-                        filteredList == null ? null : new MediaParceledListSlice<>(filteredList);
-                try {
-                    connection.callbacks.onLoadChildrenWithOptions(parentId, pls, options);
-                } catch (RemoteException ex) {
-                    // The other side is in the process of crashing.
-                    Log.w(TAG, "Calling onLoadChildren() failed for id=" + parentId
-                            + " package=" + connection.pkg);
-                }
-            }
-        };
-
-        mCurConnection = connection;
-        if (options == null) {
-            onLoadChildren(parentId, result);
-        } else {
-            onLoadChildren(parentId, result, options);
-        }
-        mCurConnection = null;
-
-        if (!result.isDone()) {
-            throw new IllegalStateException("onLoadChildren must call detach() or sendResult()"
-                    + " before returning for package=" + connection.pkg + " id=" + parentId);
-        }
-    }
-
-    private List<MediaBrowser.MediaItem> applyOptions(List<MediaBrowser.MediaItem> list,
-            final Bundle options) {
-        if (list == null) {
-            return null;
-        }
-        int page = options.getInt(MediaBrowser.EXTRA_PAGE, -1);
-        int pageSize = options.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1);
-        if (page == -1 && pageSize == -1) {
-            return list;
-        }
-        int fromIndex = pageSize * page;
-        int toIndex = fromIndex + pageSize;
-        if (page < 0 || pageSize < 1 || fromIndex >= list.size()) {
-            return Collections.EMPTY_LIST;
-        }
-        if (toIndex > list.size()) {
-            toIndex = list.size();
-        }
-        return list.subList(fromIndex, toIndex);
-    }
-
-    private void performLoadItem(String itemId, final ConnectionRecord connection,
-            final ResultReceiver receiver) {
-        final Result<MediaBrowser.MediaItem> result =
-                new Result<MediaBrowser.MediaItem>(itemId) {
-            @Override
-            void onResultSent(MediaBrowser.MediaItem item, @ResultFlags int flag) {
-                if (mConnections.get(connection.callbacks.asBinder()) != connection) {
-                    if (DBG) {
-                        Log.d(TAG, "Not sending onLoadItem result for connection that has"
-                                + " been disconnected. pkg=" + connection.pkg + " id=" + itemId);
-                    }
-                    return;
-                }
-                if ((flag & RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED) != 0) {
-                    receiver.send(RESULT_ERROR, null);
-                    return;
-                }
-                Bundle bundle = new Bundle();
-                bundle.putParcelable(KEY_MEDIA_ITEM, item);
-                receiver.send(RESULT_OK, bundle);
-            }
-        };
-
-        mCurConnection = connection;
-        onLoadItem(itemId, result);
-        mCurConnection = null;
-
-        if (!result.isDone()) {
-            throw new IllegalStateException("onLoadItem must call detach() or sendResult()"
-                    + " before returning for id=" + itemId);
-        }
-    }
-
-    /**
-     * Contains information that the browser service needs to send to the client
-     * when first connected.
-     */
-    public static final class BrowserRoot {
-        /**
-         * The lookup key for a boolean that indicates whether the browser service should return a
-         * browser root for recently played media items.
-         *
-         * <p>When creating a media browser for a given media browser service, this key can be
-         * supplied as a root hint for retrieving media items that are recently played.
-         * If the media browser service can provide such media items, the implementation must return
-         * the key in the root hint when {@link #onGetRoot(String, int, Bundle)} is called back.
-         *
-         * <p>The root hint may contain multiple keys.
-         *
-         * @see #EXTRA_OFFLINE
-         * @see #EXTRA_SUGGESTED
-         */
-        public static final String EXTRA_RECENT = "android.service.media.extra.RECENT";
-
-        /**
-         * The lookup key for a boolean that indicates whether the browser service should return a
-         * browser root for offline media items.
-         *
-         * <p>When creating a media browser for a given media browser service, this key can be
-         * supplied as a root hint for retrieving media items that are can be played without an
-         * internet connection.
-         * If the media browser service can provide such media items, the implementation must return
-         * the key in the root hint when {@link #onGetRoot(String, int, Bundle)} is called back.
-         *
-         * <p>The root hint may contain multiple keys.
-         *
-         * @see #EXTRA_RECENT
-         * @see #EXTRA_SUGGESTED
-         */
-        public static final String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE";
-
-        /**
-         * The lookup key for a boolean that indicates whether the browser service should return a
-         * browser root for suggested media items.
-         *
-         * <p>When creating a media browser for a given media browser service, this key can be
-         * supplied as a root hint for retrieving the media items suggested by the media browser
-         * service. The list of media items passed in {@link android.media.browse.MediaBrowser.SubscriptionCallback#onChildrenLoaded(String, List)}
-         * is considered ordered by relevance, first being the top suggestion.
-         * If the media browser service can provide such media items, the implementation must return
-         * the key in the root hint when {@link #onGetRoot(String, int, Bundle)} is called back.
-         *
-         * <p>The root hint may contain multiple keys.
-         *
-         * @see #EXTRA_RECENT
-         * @see #EXTRA_OFFLINE
-         */
-        public static final String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
-
-        final private String mRootId;
-        final private Bundle mExtras;
-
-        /**
-         * Constructs a browser root.
-         * @param rootId The root id for browsing.
-         * @param extras Any extras about the browser service.
-         */
-        public BrowserRoot(@NonNull String rootId, @Nullable Bundle extras) {
-            if (rootId == null) {
-                throw new IllegalArgumentException("The root id in BrowserRoot cannot be null. " +
-                        "Use null for BrowserRoot instead.");
-            }
-            mRootId = rootId;
-            mExtras = extras;
-        }
-
-        /**
-         * Gets the root id for browsing.
-         */
-        public String getRootId() {
-            return mRootId;
-        }
-
-        /**
-         * Gets any extras about the browser service.
-         */
-        public Bundle getExtras() {
-            return mExtras;
-        }
-    }
-}
diff --git a/packages/OWNERS b/packages/OWNERS
deleted file mode 100644
index 3b9fd2b..0000000
--- a/packages/OWNERS
+++ /dev/null
@@ -1,9 +0,0 @@
-akersten@google.com
-dwkang@google.com
-hdmoon@google.com
-insun@google.com
-jaewan@google.com
-jinpark@google.com
-marcone@google.com
-sungsoo@google.com
-wjia@google.com
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index c0aa477..91b7587 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -38,7 +38,8 @@
     libpowermanager \
     libmediautils \
     libmemunreachable \
-    libmedia_helper
+    libmedia_helper \
+    libvibrator
 
 LOCAL_STATIC_LIBRARIES := \
     libcpustats \
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 0d6ef46..bc99099 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -27,6 +27,7 @@
 #include <sys/time.h>
 #include <sys/resource.h>
 
+#include <android/os/IExternalVibratorService.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 #include <utils/Log.h>
@@ -122,6 +123,21 @@
     }
 }
 
+// Keep a strong reference to external vibrator service
+static sp<os::IExternalVibratorService> sExternalVibratorService;
+
+static sp<os::IExternalVibratorService> getExternalVibratorService() {
+    if (sExternalVibratorService == 0) {
+        sp <IBinder> binder = defaultServiceManager()->getService(
+            String16("external_vibrator_service"));
+        if (binder != 0) {
+            sExternalVibratorService =
+                interface_cast<os::IExternalVibratorService>(binder);
+        }
+    }
+    return sExternalVibratorService;
+}
+
 // ----------------------------------------------------------------------------
 
 std::string formatToString(audio_format_t format) {
@@ -318,6 +334,27 @@
     return ret;
 }
 
+/* static */
+int AudioFlinger::onExternalVibrationStart(const sp<os::ExternalVibration>& externalVibration) {
+    sp<os::IExternalVibratorService> evs = getExternalVibratorService();
+    if (evs != 0) {
+        int32_t ret;
+        binder::Status status = evs->onExternalVibrationStart(*externalVibration, &ret);
+        if (status.isOk()) {
+            return ret;
+        }
+    }
+    return AudioMixer::HAPTIC_SCALE_NONE;
+}
+
+/* static */
+void AudioFlinger::onExternalVibrationStop(const sp<os::ExternalVibration>& externalVibration) {
+    sp<os::IExternalVibratorService> evs = getExternalVibratorService();
+    if (evs != 0) {
+        evs->onExternalVibrationStop(*externalVibration);
+    }
+}
+
 static const char * const audio_interfaces[] = {
     AUDIO_HARDWARE_MODULE_ID_PRIMARY,
     AUDIO_HARDWARE_MODULE_ID_A2DP,
@@ -897,6 +934,40 @@
     return NO_ERROR;
 }
 
+status_t AudioFlinger::setMasterBalance(float balance)
+{
+    status_t ret = initCheck();
+    if (ret != NO_ERROR) {
+        return ret;
+    }
+
+    // check calling permissions
+    if (!settingsAllowed()) {
+        return PERMISSION_DENIED;
+    }
+
+    // check range
+    if (isnan(balance) || fabs(balance) > 1.f) {
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock _l(mLock);
+
+    // short cut.
+    if (mMasterBalance == balance) return NO_ERROR;
+
+    mMasterBalance = balance;
+
+    for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+        if (mPlaybackThreads.valueAt(i)->isDuplicating()) {
+            continue;
+        }
+        mPlaybackThreads.valueAt(i)->setMasterBalance(balance);
+    }
+
+    return NO_ERROR;
+}
+
 status_t AudioFlinger::setMode(audio_mode_t mode)
 {
     status_t ret = initCheck();
@@ -1036,6 +1107,13 @@
     return masterVolume_l();
 }
 
+status_t AudioFlinger::getMasterBalance(float *balance) const
+{
+    Mutex::Autolock _l(mLock);
+    *balance = getMasterBalance_l();
+    return NO_ERROR; // if called through binder, may return a transactional error
+}
+
 bool AudioFlinger::masterMute() const
 {
     Mutex::Autolock _l(mLock);
@@ -1047,6 +1125,11 @@
     return mMasterVolume;
 }
 
+float AudioFlinger::getMasterBalance_l() const
+{
+    return mMasterBalance;
+}
+
 bool AudioFlinger::masterMute_l() const
 {
     return mMasterMute;
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index c1169d2..d8c0da5 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -30,6 +30,7 @@
 #include <sys/types.h>
 #include <limits.h>
 
+#include <android/os/BnExternalVibrationController.h>
 #include <android-base/macros.h>
 
 #include <cutils/atomic.h>
@@ -84,6 +85,8 @@
 #include <private/media/AudioEffectShared.h>
 #include <private/media/AudioTrackShared.h>
 
+#include <vibrator/ExternalVibration.h>
+
 #include "android/media/BnAudioRecord.h"
 
 namespace android {
@@ -137,6 +140,10 @@
     virtual     float       masterVolume() const;
     virtual     bool        masterMute() const;
 
+    // Balance value must be within -1.f (left only) to 1.f (right only) inclusive.
+                status_t    setMasterBalance(float balance) override;
+                status_t    getMasterBalance(float *balance) const override;
+
     virtual     status_t    setStreamVolume(audio_stream_type_t stream, float value,
                                             audio_io_handle_t output);
     virtual     status_t    setStreamMute(audio_stream_type_t stream, bool muted);
@@ -284,6 +291,9 @@
                             const sp<MmapStreamCallback>& callback,
                             sp<MmapStreamInterface>& interface,
                             audio_port_handle_t *handle);
+
+    static int onExternalVibrationStart(const sp<os::ExternalVibration>& externalVibration);
+    static void onExternalVibrationStop(const sp<os::ExternalVibration>& externalVibration);
 private:
     // FIXME The 400 is temporarily too high until a leak of writers in media.log is fixed.
     static const size_t kLogMemorySize = 400 * 1024;
@@ -776,6 +786,7 @@
                 // member variables below are protected by mLock
                 float                               mMasterVolume;
                 bool                                mMasterMute;
+                float                               mMasterBalance = 0.f;
                 // end of variables protected by mLock
 
                 DefaultKeyedVector< audio_io_handle_t, sp<RecordThread> >    mRecordThreads;
@@ -793,6 +804,7 @@
                 Vector<AudioSessionRef*> mAudioSessionRefs;
 
                 float       masterVolume_l() const;
+                float       getMasterBalance_l() const;
                 bool        masterMute_l() const;
                 audio_module_handle_t loadHwModule_l(const char *name);
 
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index f328577..e78c98b 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -60,7 +60,6 @@
     mSinkChannelCount(FCC_2),
     mMixerBuffer(NULL),
     mMixerBufferSize(0),
-    mMixerBufferFormat(AUDIO_FORMAT_PCM_16_BIT),
     mMixerBufferState(UNDEFINED),
     mFormat(Format_Invalid),
     mSampleRate(0),
@@ -161,6 +160,7 @@
         mOutputSink = current->mOutputSink;
         mOutputSinkGen = current->mOutputSinkGen;
         mSinkChannelMask = current->mSinkChannelMask;
+        mBalance.setChannelMask(mSinkChannelMask);
         if (mOutputSink == NULL) {
             mFormat = Format_Invalid;
             mSampleRate = 0;
@@ -191,10 +191,6 @@
         free(mSinkBuffer);
         mSinkBuffer = NULL;
         if (frameCount > 0 && mSampleRate > 0) {
-            // The mixer produces either 16 bit PCM or float output, select
-            // float output if the HAL supports higher than 16 bit precision.
-            mMixerBufferFormat = mFormat.mFormat == AUDIO_FORMAT_PCM_16_BIT ?
-                    AUDIO_FORMAT_PCM_16_BIT : AUDIO_FORMAT_PCM_FLOAT;
             // FIXME new may block for unbounded time at internal mutex of the heap
             //       implementation; it would be better to have normal mixer allocate for us
             //       to avoid blocking here and to prevent possible priority inversion
@@ -295,6 +291,8 @@
                         (void *)(uintptr_t)mSinkChannelMask);
                 mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::HAPTIC_ENABLED,
                         (void *)(uintptr_t)fastTrack->mHapticPlaybackEnabled);
+                mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::HAPTIC_INTENSITY,
+                        (void *)(uintptr_t)fastTrack->mHapticIntensity);
                 mMixer->enable(name);
             }
             mGenerations[i] = fastTrack->mGeneration;
@@ -333,6 +331,8 @@
                             (void *)(uintptr_t)mSinkChannelMask);
                     mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::HAPTIC_ENABLED,
                             (void *)(uintptr_t)fastTrack->mHapticPlaybackEnabled);
+                    mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::HAPTIC_INTENSITY,
+                            (void *)(uintptr_t)fastTrack->mHapticIntensity);
                     // already enabled
                 }
                 mGenerations[i] = fastTrack->mGeneration;
@@ -471,6 +471,12 @@
             mono_blend(mMixerBuffer, mMixerBufferFormat, Format_channelCount(mFormat), frameCount,
                     true /*limit*/);
         }
+
+        // Balance must take effect after mono conversion.
+        // mBalance detects zero balance within the class for speed (not needed here).
+        mBalance.setBalance(mMasterBalance.load());
+        mBalance.process((float *)mMixerBuffer, frameCount);
+
         // prepare the buffer used to write to sink
         void *buffer = mSinkBuffer != NULL ? mSinkBuffer : mMixerBuffer;
         if (mFormat.mFormat != mMixerBufferFormat) { // sink format not the same as mixer format
diff --git a/services/audioflinger/FastMixer.h b/services/audioflinger/FastMixer.h
index 1d332e0..c31d476 100644
--- a/services/audioflinger/FastMixer.h
+++ b/services/audioflinger/FastMixer.h
@@ -18,6 +18,7 @@
 #define ANDROID_AUDIO_FAST_MIXER_H
 
 #include <atomic>
+#include <audio_utils/Balance.h>
 #include "FastThread.h"
 #include "StateQueue.h"
 #include "FastMixerState.h"
@@ -41,6 +42,8 @@
             FastMixerStateQueue* sq();
 
     virtual void setMasterMono(bool mono) { mMasterMono.store(mono); /* memory_order_seq_cst */ }
+    virtual void setMasterBalance(float balance) { mMasterBalance.store(balance); }
+    virtual float getMasterBalance() const { return mMasterBalance.load(); }
     virtual void setBoottimeOffset(int64_t boottimeOffset) {
         mBoottimeOffset.store(boottimeOffset); /* memory_order_seq_cst */
     }
@@ -74,7 +77,7 @@
     audio_channel_mask_t mSinkChannelMask;
     void*           mMixerBuffer;       // mixer output buffer.
     size_t          mMixerBufferSize;
-    audio_format_t  mMixerBufferFormat; // mixer output format: AUDIO_FORMAT_PCM_(16_BIT|FLOAT).
+    static constexpr audio_format_t mMixerBufferFormat = AUDIO_FORMAT_PCM_FLOAT;
 
     uint32_t        mAudioChannelCount; // audio channel count, excludes haptic channels.
 
@@ -89,8 +92,11 @@
     ExtendedTimestamp mTimestamp;
     int64_t         mNativeFramesWrittenButNotPresented;
 
+    audio_utils::Balance mBalance;
+
     // accessed without lock between multiple threads.
     std::atomic_bool mMasterMono;
+    std::atomic<float> mMasterBalance{};
     std::atomic_int_fast64_t mBoottimeOffset;
 
     const audio_io_handle_t mThreadIoHandle; // parent thread id for debugging purposes
diff --git a/services/audioflinger/FastMixerState.h b/services/audioflinger/FastMixerState.h
index 9d2a733..c27f2b7 100644
--- a/services/audioflinger/FastMixerState.h
+++ b/services/audioflinger/FastMixerState.h
@@ -19,6 +19,7 @@
 
 #include <audio_utils/minifloat.h>
 #include <system/audio.h>
+#include <media/AudioMixer.h>
 #include <media/ExtendedAudioBufferProvider.h>
 #include <media/nbaio/NBAIO.h>
 #include <media/nblog/NBLog.h>
@@ -48,6 +49,8 @@
     audio_format_t          mFormat;         // track format
     int                     mGeneration;     // increment when any field is assigned
     bool                    mHapticPlaybackEnabled = false; // haptic playback is enabled or not
+    AudioMixer::haptic_intensity_t mHapticIntensity = AudioMixer::HAPTIC_SCALE_NONE; // intensity of
+                                                                                     // haptic data
 };
 
 // Represents a single state of the fast mixer
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index d9f570d..bad3ca8 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -119,6 +119,15 @@
             void    setHapticPlaybackEnabled(bool hapticPlaybackEnabled) {
                 mHapticPlaybackEnabled = hapticPlaybackEnabled;
             }
+            /** Return at what intensity to play haptics, used in mixer. */
+            AudioMixer::haptic_intensity_t getHapticIntensity() const { return mHapticIntensity; }
+            /** Set intensity of haptic playback, should be set after querying vibrator service. */
+            void    setHapticIntensity(AudioMixer::haptic_intensity_t hapticIntensity) {
+                if (AudioMixer::isValidHapticIntensity(hapticIntensity)) {
+                    mHapticIntensity = hapticIntensity;
+                }
+            }
+            sp<os::ExternalVibration> getExternalVibration() const { return mExternalVibration; }
 
 protected:
     // for numerous
@@ -197,6 +206,18 @@
     sp<media::VolumeHandler>  mVolumeHandler; // handles multiple VolumeShaper configs and operations
 
     bool                mHapticPlaybackEnabled = false; // indicates haptic playback enabled or not
+    // intensity to play haptic data
+    AudioMixer::haptic_intensity_t mHapticIntensity = AudioMixer::HAPTIC_SCALE_NONE;
+    class AudioVibrationController : public os::BnExternalVibrationController {
+    public:
+        explicit AudioVibrationController(Track* track) : mTrack(track) {}
+        binder::Status mute(/*out*/ bool *ret) override;
+        binder::Status unmute(/*out*/ bool *ret) override;
+    private:
+        Track* const mTrack;
+    };
+    sp<AudioVibrationController> mAudioVibrationController;
+    sp<os::ExternalVibration>    mExternalVibration;
 
 private:
     // The following fields are only for fast tracks, and should be in a subclass
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 9f838a3..5a70864 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -38,6 +38,7 @@
 
 #include <private/media/AudioTrackShared.h>
 #include <private/android_filesystem_config.h>
+#include <audio_utils/Balance.h>
 #include <audio_utils/channels.h>
 #include <audio_utils/mono_blend.h>
 #include <audio_utils/primitives.h>
@@ -2271,6 +2272,11 @@
     }
 }
 
+void AudioFlinger::PlaybackThread::setMasterBalance(float balance)
+{
+    mMasterBalance.store(balance);
+}
+
 void AudioFlinger::PlaybackThread::setMasterMute(bool muted)
 {
     if (isDuplicating()) {
@@ -2358,15 +2364,23 @@
                     track->sharedBuffer() != 0 ? Track::FS_FILLED : Track::FS_FILLING;
         }
 
-        // Disable all haptic playback for all other active tracks when haptic playback is supported
-        // and the track contains haptic channels. Enable haptic playback for current track.
-        // TODO: Request actual haptic playback status from vibrator service
         if ((track->channelMask() & AUDIO_CHANNEL_HAPTIC_ALL) != AUDIO_CHANNEL_NONE
                 && mHapticChannelMask != AUDIO_CHANNEL_NONE) {
-            for (auto &t : mActiveTracks) {
-                t->setHapticPlaybackEnabled(false);
+            // Unlock due to VibratorService will lock for this call and will
+            // call Tracks.mute/unmute which also require thread's lock.
+            mLock.unlock();
+            const int intensity = AudioFlinger::onExternalVibrationStart(
+                    track->getExternalVibration());
+            mLock.lock();
+            // Haptic playback should be enabled by vibrator service.
+            if (track->getHapticPlaybackEnabled()) {
+                // Disable haptic playback of all active track to ensure only
+                // one track playing haptic if current track should play haptic.
+                for (const auto &t : mActiveTracks) {
+                    t->setHapticPlaybackEnabled(false);
+                }
             }
-            track->setHapticPlaybackEnabled(true);
+            track->setHapticIntensity(intensity);
         }
 
         track->mResetDone = false;
@@ -2523,6 +2537,7 @@
                 mChannelMask);
     }
     mChannelCount = audio_channel_count_from_out_mask(mChannelMask);
+    mBalance.setChannelMask(mChannelMask);
 
     // Get actual HAL format.
     status_t result = mOutput->stream->getFormat(&mHALFormat);
@@ -2642,7 +2657,7 @@
     free(mMixerBuffer);
     mMixerBuffer = NULL;
     if (mMixerBufferEnabled) {
-        mMixerBufferFormat = AUDIO_FORMAT_PCM_FLOAT; // also valid: AUDIO_FORMAT_PCM_16_BIT.
+        mMixerBufferFormat = AUDIO_FORMAT_PCM_FLOAT; // no longer valid: AUDIO_FORMAT_PCM_16_BIT.
         mMixerBufferSize = mNormalFrameCount * mChannelCount
                 * audio_bytes_per_sample(mMixerBufferFormat);
         (void)posix_memalign(&mMixerBuffer, 32, mMixerBufferSize);
@@ -3531,6 +3546,14 @@
                                true /*limit*/);
                 }
 
+                if (!hasFastMixer()) {
+                    // Balance must take effect after mono conversion.
+                    // We do it here if there is no FastMixer.
+                    // mBalance detects zero balance within the class for speed (not needed here).
+                    mBalance.setBalance(mMasterBalance.load());
+                    mBalance.process((float *)mMixerBuffer, mNormalFrameCount);
+                }
+
                 memcpy_by_audio_format(buffer, format, mMixerBuffer, mMixerBufferFormat,
                         mNormalFrameCount * (mChannelCount + mHapticChannelCount));
 
@@ -3585,6 +3608,14 @@
                            true /*limit*/);
             }
 
+            if (!hasFastMixer()) {
+                // Balance must take effect after mono conversion.
+                // We do it here if there is no FastMixer.
+                // mBalance detects zero balance within the class for speed (not needed here).
+                mBalance.setBalance(mMasterBalance.load());
+                mBalance.process((float *)mEffectBuffer, mNormalFrameCount);
+            }
+
             memcpy_by_audio_format(mSinkBuffer, mFormat, mEffectBuffer, mEffectBufferFormat,
                     mNormalFrameCount * (mChannelCount + mHapticChannelCount));
             // The sample data is partially interleaved when haptic channels exist,
@@ -3760,7 +3791,6 @@
 // removeTracks_l() must be called with ThreadBase::mLock held
 void AudioFlinger::PlaybackThread::removeTracks_l(const Vector< sp<Track> >& tracksToRemove)
 {
-    bool enabledHapticTracksRemoved = false;
     for (const auto& track : tracksToRemove) {
         mActiveTracks.remove(track);
         ALOGV("%s(%d): removing track on session %d", __func__, track->id(), track->sessionId());
@@ -3782,17 +3812,13 @@
             // remove from our tracks vector
             removeTrack_l(track);
         }
-        enabledHapticTracksRemoved |= track->getHapticPlaybackEnabled();
-    }
-    // If the thread supports haptic playback and the track playing haptic data was removed,
-    // enable haptic playback on the first active track that contains haptic channels.
-    // TODO: Query vibrator service to know which track should enable haptic playback.
-    if (enabledHapticTracksRemoved && mHapticChannelMask != AUDIO_CHANNEL_NONE) {
-        for (auto &t : mActiveTracks) {
-            if (t->channelMask() & AUDIO_CHANNEL_HAPTIC_ALL) {
-                t->setHapticPlaybackEnabled(true);
-                break;
-            }
+        if ((track->channelMask() & AUDIO_CHANNEL_HAPTIC_ALL) != AUDIO_CHANNEL_NONE
+                && mHapticChannelCount > 0) {
+            mLock.unlock();
+            // Unlock due to VibratorService will lock for this call and will
+            // call Tracks.mute/unmute which also require thread's lock.
+            AudioFlinger::onExternalVibrationStop(track->getExternalVibration());
+            mLock.lock();
         }
     }
 }
@@ -3985,6 +4011,7 @@
         // mPipeSink below
         // mNormalSink below
 {
+    setMasterBalance(audioFlinger->getMasterBalance_l());
     ALOGV("MixerThread() id=%d device=%#x type=%d", id, device, type);
     ALOGV("mSampleRate=%u, mChannelMask=%#x, mChannelCount=%u, mFormat=%#x, mFrameSize=%zu, "
             "mFrameCount=%zu, mNormalFrameCount=%zu",
@@ -4615,6 +4642,7 @@
                     fastTrack->mChannelMask = track->mChannelMask;
                     fastTrack->mFormat = track->mFormat;
                     fastTrack->mHapticPlaybackEnabled = track->getHapticPlaybackEnabled();
+                    fastTrack->mHapticIntensity = track->getHapticIntensity();
                     fastTrack->mGeneration++;
                     state->mTrackMask |= 1 << j;
                     didModify = true;
@@ -4937,6 +4965,10 @@
                 trackId,
                 AudioMixer::TRACK,
                 AudioMixer::HAPTIC_ENABLED, (void *)(uintptr_t)track->getHapticPlaybackEnabled());
+            mAudioMixer->setParameter(
+                trackId,
+                AudioMixer::TRACK,
+                AudioMixer::HAPTIC_INTENSITY, (void *)(uintptr_t)track->getHapticIntensity());
 
             // reset retry count
             track->mRetryCount = kMaxTrackRetries;
@@ -5266,6 +5298,9 @@
     dprintf(fd, "  Thread throttle time (msecs): %u\n", mThreadThrottleTimeMs);
     dprintf(fd, "  AudioMixer tracks: %s\n", mAudioMixer->trackNames().c_str());
     dprintf(fd, "  Master mono: %s\n", mMasterMono ? "on" : "off");
+    dprintf(fd, "  Master balance: %f (%s)\n", mMasterBalance.load(),
+            (hasFastMixer() ? std::to_string(mFastMixer->getMasterBalance())
+                            : mBalance.toString()).c_str());
     const double latencyMs = mTimestamp.getOutputServerLatencyMs(mSampleRate);
     if (latencyMs != 0.) {
         dprintf(fd, "  NormalMixer latency ms: %.2lf\n", latencyMs);
@@ -5333,12 +5368,30 @@
         ThreadBase::type_t type, bool systemReady)
     :   PlaybackThread(audioFlinger, output, id, device, type, systemReady)
 {
+    setMasterBalance(audioFlinger->getMasterBalance_l());
 }
 
 AudioFlinger::DirectOutputThread::~DirectOutputThread()
 {
 }
 
+void AudioFlinger::DirectOutputThread::dumpInternals(int fd, const Vector<String16>& args)
+{
+    PlaybackThread::dumpInternals(fd, args);
+    dprintf(fd, "  Master balance: %f  Left: %f  Right: %f\n",
+            mMasterBalance.load(), mMasterBalanceLeft, mMasterBalanceRight);
+}
+
+void AudioFlinger::DirectOutputThread::setMasterBalance(float balance)
+{
+    Mutex::Autolock _l(mLock);
+    if (mMasterBalance != balance) {
+        mMasterBalance.store(balance);
+        mBalance.computeStereoBalance(balance, &mMasterBalanceLeft, &mMasterBalanceRight);
+        broadcast_l();
+    }
+}
+
 void AudioFlinger::DirectOutputThread::processVolume_l(Track *track, bool lastTrack)
 {
     float left, right;
@@ -5362,12 +5415,12 @@
         if (left > GAIN_FLOAT_UNITY) {
             left = GAIN_FLOAT_UNITY;
         }
-        left *= v;
+        left *= v * mMasterBalanceLeft; // DirectOutputThread balance applied as track volume
         right = float_from_gain(gain_minifloat_unpack_right(vlr));
         if (right > GAIN_FLOAT_UNITY) {
             right = GAIN_FLOAT_UNITY;
         }
-        right *= v;
+        right *= v * mMasterBalanceRight;
     }
 
     if (lastTrack) {
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 8b8222c..1131b26 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -733,6 +733,7 @@
 
                 // VolumeInterface
     virtual     void        setMasterVolume(float value);
+    virtual     void        setMasterBalance(float balance);
     virtual     void        setMasterMute(bool muted);
     virtual     void        setStreamVolume(audio_stream_type_t stream, float value);
     virtual     void        setStreamMute(audio_stream_type_t stream, bool muted);
@@ -1027,6 +1028,8 @@
     AudioStreamOut                  *mOutput;
 
     float                           mMasterVolume;
+    std::atomic<float>              mMasterBalance{};
+    audio_utils::Balance            mBalance;
     nsecs_t                         mLastWriteTime;
     int                             mNumWrites;
     int                             mNumDelayedWrites;
@@ -1199,6 +1202,13 @@
                 // Blending with limiter is not idempotent,
                 // and blending without limiter is idempotent but inefficient to do twice.
     virtual     bool       requireMonoBlend() { return mMasterMono.load() && !hasFastMixer(); }
+
+                void       setMasterBalance(float balance) override {
+                               mMasterBalance.store(balance);
+                               if (hasFastMixer()) {
+                                   mFastMixer->setMasterBalance(balance);
+                               }
+                           }
 };
 
 class DirectOutputThread : public PlaybackThread {
@@ -1216,8 +1226,13 @@
 
     virtual     bool        checkForNewParameter_l(const String8& keyValuePair,
                                                    status_t& status);
+
+                void        dumpInternals(int fd, const Vector<String16>& args) override;
+
     virtual     void        flushHw_l();
 
+                void        setMasterBalance(float balance) override;
+
 protected:
     virtual     uint32_t    activeSleepTimeUs() const;
     virtual     uint32_t    idleSleepTimeUs() const;
@@ -1245,6 +1260,10 @@
 
     wp<Track>               mPreviousTrack;         // used to detect track switch
 
+    // This must be initialized for initial condition of mMasterBalance = 0 (disabled).
+    float                   mMasterBalanceLeft = 1.f;
+    float                   mMasterBalanceRight = 1.f;
+
 public:
     virtual     bool        hasFastMixer() const { return false; }
 
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index d23d19d..22d34b2 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -451,6 +451,12 @@
     mTee.setId(std::string("_") + std::to_string(mThreadIoHandle)
             + "_" + std::to_string(mId));
 #endif
+
+    if (channelMask & AUDIO_CHANNEL_HAPTIC_ALL) {
+        mAudioVibrationController = new AudioVibrationController(this);
+        mExternalVibration = new os::ExternalVibration(
+                mUid, "" /* pkg */, mAttr, mAudioVibrationController);
+    }
 }
 
 AudioFlinger::PlaybackThread::Track::~Track()
@@ -1336,6 +1342,40 @@
     mServerLatencyMs.store(latencyMs);
 }
 
+binder::Status AudioFlinger::PlaybackThread::Track::AudioVibrationController::mute(
+        /*out*/ bool *ret) {
+    *ret = false;
+    sp<ThreadBase> thread = mTrack->mThread.promote();
+    if (thread != 0) {
+        // Lock for updating mHapticPlaybackEnabled.
+        Mutex::Autolock _l(thread->mLock);
+        PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
+        if ((mTrack->channelMask() & AUDIO_CHANNEL_HAPTIC_ALL) != AUDIO_CHANNEL_NONE
+                && playbackThread->mHapticChannelCount > 0) {
+            mTrack->setHapticPlaybackEnabled(false);
+            *ret = true;
+        }
+    }
+    return binder::Status::ok();
+}
+
+binder::Status AudioFlinger::PlaybackThread::Track::AudioVibrationController::unmute(
+        /*out*/ bool *ret) {
+    *ret = false;
+    sp<ThreadBase> thread = mTrack->mThread.promote();
+    if (thread != 0) {
+        // Lock for updating mHapticPlaybackEnabled.
+        Mutex::Autolock _l(thread->mLock);
+        PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
+        if ((mTrack->channelMask() & AUDIO_CHANNEL_HAPTIC_ALL) != AUDIO_CHANNEL_NONE
+                && playbackThread->mHapticChannelCount > 0) {
+            mTrack->setHapticPlaybackEnabled(true);
+            *ret = true;
+        }
+    }
+    return binder::Status::ok();
+}
+
 // ----------------------------------------------------------------------------
 #undef LOG_TAG
 #define LOG_TAG "AF::OutputTrack"
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index 3b9411a..cd10c82 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -411,11 +411,11 @@
             if ((rule == RULE_EXCLUDE_UID || rule == RULE_MATCH_UID)
                     && uid == mix->mCriteria[j].mValue.mUid) {
                 foundUidRule = true;
-                criteriaToRemove.push_back(j);
+                criteriaToRemove.insert(criteriaToRemove.begin(), j);
             }
         }
         if (foundUidRule) {
-            for (size_t j = criteriaToRemove.size() - 1; j >= 0; j--) {
+            for (size_t j = 0; j < criteriaToRemove.size(); j++) {
                 mix->mCriteria.removeAt(criteriaToRemove[j]);
             }
         }
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index dc5b238..4cb1e17 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -129,7 +129,7 @@
 ssize_t DeviceVector::indexOf(const sp<DeviceDescriptor>& item) const
 {
     for (size_t i = 0; i < size(); i++) {
-        if (item->equals(itemAt(i))) {
+        if (itemAt(i)->equals(item)) { // item may be null sp<>, i.e. AUDIO_DEVICE_NONE
             return i;
         }
     }
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index 85d9bce..e0b233d 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -332,10 +332,8 @@
         if (moduleDevice) {
             if (encodedFormat != AUDIO_FORMAT_DEFAULT) {
                 moduleDevice->setEncodedFormat(encodedFormat);
-                if (moduleDevice->address() != devAddress) {
-                    moduleDevice->setAddress(devAddress);
-                }
             }
+            moduleDevice->setAddress(devAddress);
             if (allowToCreate) {
                 moduleDevice->attach(hwModule);
             }
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index cf9c298..d7c7b4d 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -555,7 +555,6 @@
         muteWaitMs = setOutputDevices(mPrimaryOutput, rxDevices, true, delayMs);
     } else { // create RX path audio patch
         mCallRxPatch = createTelephonyPatch(true /*isRx*/, rxDevices.itemAt(0), delayMs);
-        ALOG_ASSERT(createTxPatch, "No Tx Patch will be created, nor legacy routing done");
     }
     if (createTxPatch) { // create TX path audio patch
         mCallTxPatch = createTelephonyPatch(false /*isRx*/, txSourceDevice, delayMs);
@@ -5063,7 +5062,7 @@
     }
 
     // If we are not in call and no client is active on this input, this methods returns
-    // AUDIO_DEVICE_NONE, causing the patch on the input stream to be released.
+    // a null sp<>, causing the patch on the input stream to be released.
     audio_attributes_t attributes = inputDesc->getHighestPriorityAttributes();
     if (attributes.source == AUDIO_SOURCE_DEFAULT && isInCall()) {
         attributes.source = AUDIO_SOURCE_VOICE_COMMUNICATION;
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 49c541c..45fb174 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -525,7 +525,7 @@
         static constexpr char kAudioPolicyActiveDevice[] =
                 "android.media.audiopolicy.active.device";
 
-        MediaAnalyticsItem *item = new MediaAnalyticsItem(kAudioPolicy);
+        MediaAnalyticsItem *item = MediaAnalyticsItem::create(kAudioPolicy);
         if (item != NULL) {
 
             item->setInt32(kAudioPolicyStatus, status);
diff --git a/services/mediaanalytics/Android.bp b/services/mediaanalytics/Android.bp
new file mode 100644
index 0000000..c93c120
--- /dev/null
+++ b/services/mediaanalytics/Android.bp
@@ -0,0 +1,49 @@
+// Media Statistics service
+//
+
+cc_binary {
+    name: "mediametrics",
+
+    srcs: [
+        "main_mediametrics.cpp",
+        "MediaAnalyticsService.cpp",
+    ],
+
+    shared_libs: [
+        "libcutils",
+        "liblog",
+        "libmedia",
+        "libutils",
+        "libbinder",
+        "libdl",
+        "libgui",
+        "libmedia",
+        "libmediautils",
+        "libmediametrics",
+        "libstagefright_foundation",
+        "libutils",
+    ],
+
+    static_libs: ["libregistermsext"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/av/media/libstagefright/rtsp",
+        "frameworks/av/media/libstagefright/webm",
+        "frameworks/av/include/media",
+        "frameworks/av/include/camera",
+        "frameworks/native/include/media/openmax",
+        "frameworks/native/include/media/hardware",
+        "external/tremolo/Tremolo",
+    ],
+
+    init_rc: ["mediametrics.rc"],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-Wno-error=deprecated-declarations",
+    ],
+    clang: true,
+
+}
diff --git a/services/mediaanalytics/Android.mk b/services/mediaanalytics/Android.mk
deleted file mode 100644
index 5b20e61..0000000
--- a/services/mediaanalytics/Android.mk
+++ /dev/null
@@ -1,47 +0,0 @@
-# Media Statistics service
-#
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-    main_mediametrics.cpp              \
-    MediaAnalyticsService.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-    libcutils                   \
-    liblog                      \
-    libmedia                    \
-    libutils                    \
-    libbinder                   \
-    libdl                       \
-    libgui                      \
-    libmedia                    \
-    libmediautils               \
-    libmediametrics             \
-    libstagefright_foundation   \
-    libutils
-
-LOCAL_STATIC_LIBRARIES := \
-        libregistermsext
-
-LOCAL_C_INCLUDES :=                                                 \
-    $(TOP)/frameworks/av/media/libstagefright/include               \
-    $(TOP)/frameworks/av/media/libstagefright/rtsp                  \
-    $(TOP)/frameworks/av/media/libstagefright/wifi-display          \
-    $(TOP)/frameworks/av/media/libstagefright/webm                  \
-    $(TOP)/frameworks/av/include/media                              \
-    $(TOP)/frameworks/av/include/camera                             \
-    $(TOP)/frameworks/native/include/media/openmax                  \
-    $(TOP)/frameworks/native/include/media/hardware                 \
-    $(TOP)/external/tremolo/Tremolo
-
-
-LOCAL_MODULE:= mediametrics
-
-LOCAL_INIT_RC := mediametrics.rc
-
-LOCAL_CFLAGS := -Werror -Wall -Wno-error=deprecated-declarations
-LOCAL_CLANG := true
-
-include $(BUILD_EXECUTABLE)
diff --git a/services/mediacodec/seccomp_policy/mediacodec-arm.policy b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
index edf4dab..9bdd4c8 100644
--- a/services/mediacodec/seccomp_policy/mediacodec-arm.policy
+++ b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
@@ -13,6 +13,9 @@
 ppoll: 1
 mmap2: 1
 getrandom: 1
+memfd_create: 1
+ftruncate: 1
+ftruncate64: 1
 
 # mremap: Ensure |flags| are (MREMAP_MAYMOVE | MREMAP_FIXED) TODO: Once minijail
 # parser support for '<' is in this needs to be modified to also prevent
diff --git a/services/mediacodec/seccomp_policy/mediacodec-x86.policy b/services/mediacodec/seccomp_policy/mediacodec-x86.policy
index 6d88c84..a48cedb 100644
--- a/services/mediacodec/seccomp_policy/mediacodec-x86.policy
+++ b/services/mediacodec/seccomp_policy/mediacodec-x86.policy
@@ -55,6 +55,9 @@
 nanosleep: 1
 sched_setscheduler: 1
 uname: 1
+memfd_create: 1
+ftruncate: 1
+ftruncate64: 1
 
 # Required by AddressSanitizer
 gettid: 1
diff --git a/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy b/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy
index 588141a..02cedba 100644
--- a/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy
+++ b/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy
@@ -21,6 +21,9 @@
 ppoll: 1
 mprotect: arg2 in ~PROT_EXEC || arg2 in ~PROT_WRITE
 mmap2: arg2 in ~PROT_EXEC || arg2 in ~PROT_WRITE
+memfd_create: 1
+ftruncate: 1
+ftruncate64: 1
 
 # mremap: Ensure |flags| are (MREMAP_MAYMOVE | MREMAP_FIXED) TODO: Once minijail
 # parser support for '<' is in this needs to be modified to also prevent
diff --git a/services/mediacodec/seccomp_policy/mediaswcodec-arm64.policy b/services/mediacodec/seccomp_policy/mediaswcodec-arm64.policy
index 1bee1b5..78ecaf5 100644
--- a/services/mediacodec/seccomp_policy/mediaswcodec-arm64.policy
+++ b/services/mediacodec/seccomp_policy/mediaswcodec-arm64.policy
@@ -26,6 +26,9 @@
 fstat: 1
 newfstatat: 1
 fstatfs: 1
+memfd_create: 1
+ftruncate: 1
+ftruncate64: 1
 
 # mremap: Ensure |flags| are (MREMAP_MAYMOVE | MREMAP_FIXED) TODO: Once minijail
 # parser support for '<' is in this needs to be modified to also prevent
diff --git a/services/mediaresourcemanager/Android.bp b/services/mediaresourcemanager/Android.bp
new file mode 100644
index 0000000..1c63f64
--- /dev/null
+++ b/services/mediaresourcemanager/Android.bp
@@ -0,0 +1,28 @@
+
+
+cc_library_shared {
+    name: "libresourcemanagerservice",
+
+    srcs: [
+        "ResourceManagerService.cpp",
+        "ServiceLog.cpp",
+    ],
+
+    shared_libs: [
+        "libmedia",
+        "libmediautils",
+        "libbinder",
+        "libutils",
+        "liblog",
+    ],
+
+    compile_multilib: "32",
+
+    include_dirs: ["frameworks/av/include"],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+}
diff --git a/services/mediaresourcemanager/Android.mk b/services/mediaresourcemanager/Android.mk
deleted file mode 100644
index 5823036..0000000
--- a/services/mediaresourcemanager/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := ResourceManagerService.cpp ServiceLog.cpp
-
-LOCAL_SHARED_LIBRARIES := libmedia libmediautils libbinder libutils liblog
-
-LOCAL_MODULE:= libresourcemanagerservice
-
-LOCAL_32_BIT_ONLY := true
-
-LOCAL_C_INCLUDES += \
-    frameworks/av/include
-
-LOCAL_CFLAGS += -Werror -Wall
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))