Merge "MediaSession2: Fix bug in runtest.sh for finding test apk"
diff --git a/camera/ndk/include/camera/NdkCameraDevice.h b/camera/ndk/include/camera/NdkCameraDevice.h
index c0eb5c1..f425830 100644
--- a/camera/ndk/include/camera/NdkCameraDevice.h
+++ b/camera/ndk/include/camera/NdkCameraDevice.h
@@ -252,35 +252,6 @@
      */
     TEMPLATE_MANUAL = 6,
 
-    /**
-     * A template for selecting camera parameters that match TEMPLATE_PREVIEW as closely as
-     * possible while improving the camera output for motion tracking use cases.
-     *
-     * <p>This template is best used by applications that are frequently switching between motion
-     * tracking use cases and regular still capture use cases, to minimize the IQ changes
-     * when swapping use cases.</p>
-     *
-     * <p>This template is guaranteed to be supported on camera devices that support the
-     * {@link ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING} capability.</p>
-     *
-     * @see ACameraDevice_createCaptureRequest
-     */
-    TEMPLATE_MOTION_TRACKING_PREVIEW = 7,
-
-    /**
-     * A template for selecting camera parameters that maximize the quality of camera output for
-     * motion tracking use cases.
-     *
-     * <p>This template is best used by applications dedicated to motion tracking applications,
-     * which aren't concerned about fast switches between motion tracking and other use cases.</p>
-     *
-     * <p>This template is guaranteed to be supported on camera devices that support the
-     * {@link ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING} capability.</p>
-     *
-     * @see ACameraDevice_createCaptureRequest
-     */
-    TEMPLATE_MOTION_TRACKING_BEST = 8,
-
 } ACameraDevice_request_template;
 
 /**
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 588e96a..d35a52b 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -2453,9 +2453,6 @@
      *
      * <p>Different calibration methods and use cases can produce better or worse results
      * depending on the selected coordinate origin.</p>
-     * <p>For devices designed to support the MOTION_TRACKING capability, the GYROSCOPE origin
-     * makes device calibration and later usage by applications combining camera and gyroscope
-     * information together simpler.</p>
      */
     ACAMERA_LENS_POSE_REFERENCE =                               // byte (acamera_metadata_enum_android_lens_pose_reference_t)
             ACAMERA_LENS_START + 12,
@@ -4565,7 +4562,7 @@
     ACAMERA_STATISTICS_LENS_SHADING_MAP_MODE =                  // byte (acamera_metadata_enum_android_statistics_lens_shading_map_mode_t)
             ACAMERA_STATISTICS_START + 16,
     /**
-     * <p>Whether the camera device outputs the OIS data in output
+     * <p>A control for selecting whether OIS position information is included in output
      * result metadata.</p>
      *
      * <p>Type: byte (acamera_metadata_enum_android_statistics_ois_data_mode_t)</p>
@@ -4578,7 +4575,7 @@
      *
      * <p>When set to ON,
      * ACAMERA_STATISTICS_OIS_TIMESTAMPS, android.statistics.oisShiftPixelX,
-     * android.statistics.oisShiftPixelY will provide OIS data in the output result metadata.</p>
+     * and android.statistics.oisShiftPixelY provide OIS data in the output result metadata.</p>
      *
      * @see ACAMERA_STATISTICS_OIS_TIMESTAMPS
      */
@@ -6601,7 +6598,7 @@
     /**
      * <p>The value of ACAMERA_LENS_POSE_TRANSLATION is relative to the optical center of
      * the largest camera device facing the same direction as this camera.</p>
-     * <p>This default value for API levels before Android P.</p>
+     * <p>This is the default value for API levels before Android P.</p>
      *
      * @see ACAMERA_LENS_POSE_TRANSLATION
      */
@@ -6610,7 +6607,6 @@
     /**
      * <p>The value of ACAMERA_LENS_POSE_TRANSLATION is relative to the position of the
      * primary gyroscope of this Android device.</p>
-     * <p>This is the value reported by all devices that support the MOTION_TRACKING capability.</p>
      *
      * @see ACAMERA_LENS_POSE_TRANSLATION
      */
@@ -6974,46 +6970,12 @@
     ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT              = 8,
 
     /**
-     * <p>The device supports controls and metadata required for accurate motion tracking for
-     * use cases such as augmented reality, electronic image stabilization, and so on.</p>
-     * <p>This means this camera device has accurate optical calibration and timestamps relative
-     * to the inertial sensors.</p>
-     * <p>This capability requires the camera device to support the following:</p>
-     * <ul>
-     * <li>Capture request templates <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#TEMPLATE_MOTION_TRACKING_PREVIEW">CameraDevice#TEMPLATE_MOTION_TRACKING_PREVIEW</a> and <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#TEMPLATE_MOTION_TRACKING_BEST">CameraDevice#TEMPLATE_MOTION_TRACKING_BEST</a> are defined.</li>
-     * <li>The stream configurations listed in <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">CameraDevice#createCaptureSession</a> for MOTION_TRACKING are
-     *   supported, either at 30 or 60fps maximum frame rate.</li>
-     * <li>The following camera characteristics and capture result metadata are provided:<ul>
-     * <li>ACAMERA_LENS_INTRINSIC_CALIBRATION</li>
-     * <li>ACAMERA_LENS_RADIAL_DISTORTION</li>
-     * <li>ACAMERA_LENS_POSE_ROTATION</li>
-     * <li>ACAMERA_LENS_POSE_TRANSLATION</li>
-     * <li>ACAMERA_LENS_POSE_REFERENCE with value GYROSCOPE</li>
-     * </ul>
-     * </li>
-     * <li>The ACAMERA_SENSOR_INFO_TIMESTAMP_SOURCE field has value <code>REALTIME</code>. When compared to
-     *   timestamps from the device's gyroscopes, the clock difference for events occuring at
-     *   the same actual time instant will be less than 1 ms.</li>
-     * <li>The value of the ACAMERA_SENSOR_ROLLING_SHUTTER_SKEW field is accurate to within 1 ms.</li>
-     * <li>The value of ACAMERA_SENSOR_EXPOSURE_TIME is guaranteed to be available in the
-     *   capture result.</li>
-     * <li>The ACAMERA_CONTROL_CAPTURE_INTENT control supports MOTION_TRACKING to limit maximum
-     *   exposure to 20 milliseconds.</li>
-     * <li>The stream configurations required for MOTION_TRACKING (listed at <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">CameraDevice#createCaptureSession</a>) can operate at least at
-     *   30fps; optionally, they can operate at 60fps, and '[60, 60]' is listed in
-     *   ACAMERA_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES.</li>
-     * </ul>
+     * <p>The camera device supports the MOTION_TRACKING value for
+     * ACAMERA_CONTROL_CAPTURE_INTENT, which limits maximum exposure time to 20 ms.</p>
+     * <p>This limits the motion blur of capture images, resulting in better image tracking
+     * results for use cases such as image stabilization or augmented reality.</p>
      *
-     * @see ACAMERA_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES
      * @see ACAMERA_CONTROL_CAPTURE_INTENT
-     * @see ACAMERA_LENS_INTRINSIC_CALIBRATION
-     * @see ACAMERA_LENS_POSE_REFERENCE
-     * @see ACAMERA_LENS_POSE_ROTATION
-     * @see ACAMERA_LENS_POSE_TRANSLATION
-     * @see ACAMERA_LENS_RADIAL_DISTORTION
-     * @see ACAMERA_SENSOR_EXPOSURE_TIME
-     * @see ACAMERA_SENSOR_INFO_TIMESTAMP_SOURCE
-     * @see ACAMERA_SENSOR_ROLLING_SHUTTER_SKEW
      */
     ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING           = 10,
 
diff --git a/drm/libmediadrm/CryptoHal.cpp b/drm/libmediadrm/CryptoHal.cpp
index 2114d40..4377154 100644
--- a/drm/libmediadrm/CryptoHal.cpp
+++ b/drm/libmediadrm/CryptoHal.cpp
@@ -118,15 +118,24 @@
 
     auto manager = ::IServiceManager::getService();
     if (manager != NULL) {
-        manager->listByInterface(ICryptoFactory::descriptor,
+        manager->listByInterface(drm::V1_0::ICryptoFactory::descriptor,
                 [&factories](const hidl_vec<hidl_string> &registered) {
                     for (const auto &instance : registered) {
-                        auto factory = ICryptoFactory::getService(instance);
+                        auto factory = drm::V1_0::ICryptoFactory::getService(instance);
                         if (factory != NULL) {
+                            ALOGD("found drm@1.0 ICryptoFactory %s", instance.c_str());
                             factories.push_back(factory);
-                            ALOGI("makeCryptoFactories: factory instance %s is %s",
-                                    instance.c_str(),
-                                    factory->isRemote() ? "Remote" : "Not Remote");
+                        }
+                    }
+                }
+            );
+        manager->listByInterface(drm::V1_1::ICryptoFactory::descriptor,
+                [&factories](const hidl_vec<hidl_string> &registered) {
+                    for (const auto &instance : registered) {
+                        auto factory = drm::V1_1::ICryptoFactory::getService(instance);
+                        if (factory != NULL) {
+                            ALOGD("found drm@1.1 ICryptoFactory %s", instance.c_str());
+                            factories.push_back(factory);
                         }
                     }
                 }
@@ -137,7 +146,7 @@
         // must be in passthrough mode, load the default passthrough service
         auto passthrough = ICryptoFactory::getService();
         if (passthrough != NULL) {
-            ALOGI("makeCryptoFactories: using default crypto instance");
+            ALOGI("makeCryptoFactories: using default passthrough crypto instance");
             factories.push_back(passthrough);
         } else {
             ALOGE("Failed to find any crypto factories");
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index 07cec01..039e1e9 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -21,8 +21,6 @@
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 
-#include <android/hardware/drm/1.0/IDrmFactory.h>
-#include <android/hardware/drm/1.0/IDrmPlugin.h>
 #include <android/hardware/drm/1.0/types.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
 #include <hidl/ServiceManagement.h>
@@ -271,15 +269,24 @@
     auto manager = hardware::defaultServiceManager();
 
     if (manager != NULL) {
-        manager->listByInterface(IDrmFactory::descriptor,
+        manager->listByInterface(drm::V1_0::IDrmFactory::descriptor,
                 [&factories](const hidl_vec<hidl_string> &registered) {
                     for (const auto &instance : registered) {
-                        auto factory = IDrmFactory::getService(instance);
+                        auto factory = drm::V1_0::IDrmFactory::getService(instance);
                         if (factory != NULL) {
+                            ALOGD("found drm@1.0 IDrmFactory %s", instance.c_str());
                             factories.push_back(factory);
-                            ALOGI("makeDrmFactories: factory instance %s is %s",
-                                    instance.c_str(),
-                                    factory->isRemote() ? "Remote" : "Not Remote");
+                        }
+                    }
+                }
+            );
+        manager->listByInterface(drm::V1_1::IDrmFactory::descriptor,
+                [&factories](const hidl_vec<hidl_string> &registered) {
+                    for (const auto &instance : registered) {
+                        auto factory = drm::V1_1::IDrmFactory::getService(instance);
+                        if (factory != NULL) {
+                            ALOGD("found drm@1.1 IDrmFactory %s", instance.c_str());
+                            factories.push_back(factory);
                         }
                     }
                 }
@@ -290,7 +297,7 @@
         // must be in passthrough mode, load the default passthrough service
         auto passthrough = IDrmFactory::getService();
         if (passthrough != NULL) {
-            ALOGI("makeDrmFactories: using default drm instance");
+            ALOGI("makeDrmFactories: using default passthrough drm instance");
             factories.push_back(passthrough);
         } else {
             ALOGE("Failed to find any drm factories");
@@ -510,24 +517,62 @@
     return OK;
 }
 
-status_t DrmHal::openSession(Vector<uint8_t> &sessionId) {
+status_t DrmHal::openSession(DrmPlugin::SecurityLevel level,
+        Vector<uint8_t> &sessionId) {
     Mutex::Autolock autoLock(mLock);
     INIT_CHECK();
 
-    status_t  err = UNKNOWN_ERROR;
+    SecurityLevel hSecurityLevel;
+    bool setSecurityLevel = true;
 
+    switch(level) {
+    case DrmPlugin::kSecurityLevelSwSecureCrypto:
+        hSecurityLevel = SecurityLevel::SW_SECURE_CRYPTO;
+        break;
+    case DrmPlugin::kSecurityLevelSwSecureDecode:
+        hSecurityLevel = SecurityLevel::SW_SECURE_DECODE;
+        break;
+    case DrmPlugin::kSecurityLevelHwSecureCrypto:
+        hSecurityLevel = SecurityLevel::HW_SECURE_CRYPTO;
+        break;
+    case DrmPlugin::kSecurityLevelHwSecureDecode:
+        hSecurityLevel = SecurityLevel::HW_SECURE_DECODE;
+        break;
+    case DrmPlugin::kSecurityLevelHwSecureAll:
+        hSecurityLevel = SecurityLevel::HW_SECURE_ALL;
+        break;
+    case DrmPlugin::kSecurityLevelMax:
+        setSecurityLevel = false;
+        break;
+    default:
+        return ERROR_DRM_CANNOT_HANDLE;
+    }
+
+    status_t  err = UNKNOWN_ERROR;
     bool retry = true;
     do {
         hidl_vec<uint8_t> hSessionId;
 
-        Return<void> hResult = mPlugin->openSession(
-                [&](Status status, const hidl_vec<uint8_t>& id) {
-                    if (status == Status::OK) {
-                        sessionId = toVector(id);
+        Return<void> hResult;
+        if (mPluginV1_1 == NULL || !setSecurityLevel) {
+            hResult = mPlugin->openSession(
+                    [&](Status status,const hidl_vec<uint8_t>& id) {
+                        if (status == Status::OK) {
+                            sessionId = toVector(id);
+                        }
+                        err = toStatusT(status);
                     }
-                    err = toStatusT(status);
-                }
-            );
+                );
+        } else {
+            hResult = mPluginV1_1->openSession_1_1(hSecurityLevel,
+                    [&](Status status, const hidl_vec<uint8_t>& id) {
+                        if (status == Status::OK) {
+                            sessionId = toVector(id);
+                        }
+                        err = toStatusT(status);
+                    }
+                );
+        }
 
         if (!hResult.isOk()) {
             err = DEAD_OBJECT;
@@ -979,42 +1024,6 @@
     return hResult.isOk() ? err : DEAD_OBJECT;
 }
 
-status_t DrmHal::setSecurityLevel(Vector<uint8_t> const &sessionId,
-        const DrmPlugin::SecurityLevel& level) {
-    Mutex::Autolock autoLock(mLock);
-    INIT_CHECK();
-
-    if (mPluginV1_1 == NULL) {
-        return ERROR_DRM_CANNOT_HANDLE;
-    }
-
-    SecurityLevel hSecurityLevel;
-
-    switch(level) {
-    case DrmPlugin::kSecurityLevelSwSecureCrypto:
-        hSecurityLevel = SecurityLevel::SW_SECURE_CRYPTO;
-        break;
-    case DrmPlugin::kSecurityLevelSwSecureDecode:
-        hSecurityLevel = SecurityLevel::SW_SECURE_DECODE;
-        break;
-    case DrmPlugin::kSecurityLevelHwSecureCrypto:
-        hSecurityLevel = SecurityLevel::HW_SECURE_CRYPTO;
-        break;
-    case DrmPlugin::kSecurityLevelHwSecureDecode:
-        hSecurityLevel = SecurityLevel::HW_SECURE_DECODE;
-        break;
-    case DrmPlugin::kSecurityLevelHwSecureAll:
-        hSecurityLevel = SecurityLevel::HW_SECURE_ALL;
-        break;
-    default:
-        return ERROR_DRM_CANNOT_HANDLE;
-    }
-
-    Status status = mPluginV1_1->setSecurityLevel(toHidlVec(sessionId),
-            hSecurityLevel);
-    return toStatusT(status);
-}
-
 status_t DrmHal::getPropertyString(String8 const &name, String8 &value ) const {
     Mutex::Autolock autoLock(mLock);
     return getPropertyStringInternal(name, value);
diff --git a/drm/libmediadrm/IDrm.cpp b/drm/libmediadrm/IDrm.cpp
index 63a9562..9f54dba 100644
--- a/drm/libmediadrm/IDrm.cpp
+++ b/drm/libmediadrm/IDrm.cpp
@@ -60,7 +60,6 @@
     GET_HDCP_LEVELS,
     GET_NUMBER_OF_SESSIONS,
     GET_SECURITY_LEVEL,
-    SET_SECURITY_LEVEL,
     REMOVE_SECURE_STOP,
     GET_SECURE_STOP_IDS
 };
@@ -121,9 +120,11 @@
         return reply.readInt32();
     }
 
-    virtual status_t openSession(Vector<uint8_t> &sessionId) {
+    virtual status_t openSession(DrmPlugin::SecurityLevel securityLevel,
+            Vector<uint8_t> &sessionId) {
         Parcel data, reply;
         data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
+        data.writeInt32(securityLevel);
 
         status_t status = remote()->transact(OPEN_SESSION, data, &reply);
         if (status != OK) {
@@ -448,23 +449,6 @@
         return reply.readInt32();
     }
 
-    virtual status_t setSecurityLevel(Vector<uint8_t> const &sessionId,
-            const DrmPlugin::SecurityLevel& level) {
-        Parcel data, reply;
-
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        writeVector(data, sessionId);
-        data.writeInt32(static_cast<uint32_t>(level));
-
-        status_t status = remote()->transact(SET_SECURITY_LEVEL, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-
-        return reply.readInt32();
-    }
-
     virtual status_t getPropertyByteArray(String8 const &name, Vector<uint8_t> &value) const {
         Parcel data, reply;
         data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
@@ -742,8 +726,10 @@
         case OPEN_SESSION:
         {
             CHECK_INTERFACE(IDrm, data, reply);
+            DrmPlugin::SecurityLevel level =
+                    static_cast<DrmPlugin::SecurityLevel>(data.readInt32());
             Vector<uint8_t> sessionId;
-            status_t result = openSession(sessionId);
+            status_t result = openSession(level, sessionId);
             writeVector(reply, sessionId);
             reply->writeInt32(result);
             return OK;
@@ -977,18 +963,6 @@
             return OK;
         }
 
-        case SET_SECURITY_LEVEL:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            Vector<uint8_t> sessionId;
-            readVector(data, sessionId);
-            DrmPlugin::SecurityLevel level =
-                    static_cast<DrmPlugin::SecurityLevel>(data.readInt32());
-            status_t result = setSecurityLevel(sessionId, level);
-            reply->writeInt32(result);
-            return OK;
-        }
-
         case GET_PROPERTY_STRING:
         {
             CHECK_INTERFACE(IDrm, data, reply);
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
index ec75896..d921d9e 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
@@ -73,12 +73,24 @@
     mByteArrayProperties[kMetricsKey] = valueVector;
 }
 
+
 Return<void> DrmPlugin::openSession(openSession_cb _hidl_cb) {
     sp<Session> session = mSessionLibrary->createSession();
     std::vector<uint8_t> sessionId = session->sessionId();
 
-    setSecurityLevel(sessionId, SecurityLevel::SW_SECURE_CRYPTO);
-    _hidl_cb(Status::OK, toHidlVec(sessionId));
+    Status status = setSecurityLevel(sessionId, SecurityLevel::SW_SECURE_CRYPTO);
+    _hidl_cb(status, toHidlVec(sessionId));
+    mOpenSessionOkCount++;
+    return Void();
+}
+
+Return<void> DrmPlugin::openSession_1_1(SecurityLevel securityLevel,
+        openSession_1_1_cb _hidl_cb) {
+    sp<Session> session = mSessionLibrary->createSession();
+    std::vector<uint8_t> sessionId = session->sessionId();
+
+    Status status = setSecurityLevel(sessionId, securityLevel);
+    _hidl_cb(status, toHidlVec(sessionId));
     mOpenSessionOkCount++;
     return Void();
 }
@@ -344,8 +356,8 @@
         return Status::BAD_VALUE;
     }
 
-    if (level > SecurityLevel::HW_SECURE_ALL) {
-        ALOGE("Cannot set invalid security level");
+    if (level > SecurityLevel::SW_SECURE_CRYPTO) {
+        ALOGE("Cannot set security level > max");
         return Status::BAD_VALUE;
     }
 
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
index 64c8262..5d12598 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
@@ -53,6 +53,8 @@
     virtual ~DrmPlugin() {}
 
     Return<void> openSession(openSession_cb _hidl_cb) override;
+    Return<void> openSession_1_1(SecurityLevel securityLevel,
+            openSession_cb _hidl_cb) override;
 
     Return<Status> closeSession(const hidl_vec<uint8_t>& sessionId) override;
 
@@ -162,9 +164,6 @@
     Return<void> getSecurityLevel(const hidl_vec<uint8_t>& sessionId,
             getSecurityLevel_cb _hidl_cb) override;
 
-    Return<Status> setSecurityLevel(const hidl_vec<uint8_t>& sessionId,
-            SecurityLevel level) override;
-
     Return<void> getMetrics(getMetrics_cb _hidl_cb) override;
 
     Return<void> getPropertyString(
@@ -333,6 +332,9 @@
     void initProperties();
     void setPlayPolicy();
 
+    Return<Status> setSecurityLevel(const hidl_vec<uint8_t>& sessionId,
+            SecurityLevel level);
+
     std::vector<KeyValue> mPlayPolicy;
     std::map<std::string, std::string> mStringProperties;
     std::map<std::string, std::vector<uint8_t> > mByteArrayProperties;
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 9dfb514..1c4a80e 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -904,6 +904,7 @@
                                 audio_session_t session,
                                 pid_t pid,
                                 uid_t uid,
+                                const String16& opPackageName,
                                 const audio_config_base_t *config,
                                 audio_input_flags_t flags,
                                 audio_port_handle_t *selectedDeviceId,
@@ -912,35 +913,29 @@
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
     if (aps == 0) return NO_INIT;
     return aps->getInputForAttr(
-            attr, input, session, pid, uid,
+            attr, input, session, pid, uid, opPackageName,
             config, flags, selectedDeviceId, portId);
 }
 
-status_t AudioSystem::startInput(audio_io_handle_t input,
-                                 audio_session_t session,
-                                 audio_devices_t device,
-                                 uid_t uid,
-                                 bool *silenced)
+status_t AudioSystem::startInput(audio_port_handle_t portId, bool *silenced)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
     if (aps == 0) return PERMISSION_DENIED;
-    return aps->startInput(input, session, device, uid, silenced);
+    return aps->startInput(portId, silenced);
 }
 
-status_t AudioSystem::stopInput(audio_io_handle_t input,
-                                audio_session_t session)
+status_t AudioSystem::stopInput(audio_port_handle_t portId)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
     if (aps == 0) return PERMISSION_DENIED;
-    return aps->stopInput(input, session);
+    return aps->stopInput(portId);
 }
 
-void AudioSystem::releaseInput(audio_io_handle_t input,
-                               audio_session_t session)
+void AudioSystem::releaseInput(audio_port_handle_t portId)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
     if (aps == 0) return;
-    aps->releaseInput(input, session);
+    aps->releaseInput(portId);
 }
 
 status_t AudioSystem::initStreamVolume(audio_stream_type_t stream,
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index a24a099..8f5ff30 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -285,6 +285,7 @@
                                      audio_session_t session,
                                      pid_t pid,
                                      uid_t uid,
+                                     const String16& opPackageName,
                                      const audio_config_base_t *config,
                                      audio_input_flags_t flags,
                                      audio_port_handle_t *selectedDeviceId,
@@ -313,6 +314,7 @@
         data.writeInt32(session);
         data.writeInt32(pid);
         data.writeInt32(uid);
+        data.writeString16(opPackageName);
         data.write(config, sizeof(audio_config_base_t));
         data.writeInt32(flags);
         data.writeInt32(*selectedDeviceId);
@@ -331,18 +333,12 @@
         return NO_ERROR;
     }
 
-    virtual status_t startInput(audio_io_handle_t input,
-                                audio_session_t session,
-                                audio_devices_t device,
-                                uid_t uid,
+    virtual status_t startInput(audio_port_handle_t portId,
                                 bool *silenced)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
-        data.writeInt32(input);
-        data.writeInt32(session);
-        data.writeInt32(device);
-        data.writeInt32(uid);
+        data.writeInt32(portId);
         data.writeInt32(*silenced ? 1 : 0);
         remote()->transact(START_INPUT, data, &reply);
         status_t status = static_cast <status_t> (reply.readInt32());
@@ -350,24 +346,20 @@
         return status;
     }
 
-    virtual status_t stopInput(audio_io_handle_t input,
-                               audio_session_t session)
+    virtual status_t stopInput(audio_port_handle_t portId)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
-        data.writeInt32(input);
-        data.writeInt32(session);
+        data.writeInt32(portId);
         remote()->transact(STOP_INPUT, data, &reply);
         return static_cast <status_t> (reply.readInt32());
     }
 
-    virtual void releaseInput(audio_io_handle_t input,
-                              audio_session_t session)
+    virtual void releaseInput(audio_port_handle_t portId)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
-        data.writeInt32(input);
-        data.writeInt32(session);
+        data.writeInt32(portId);
         remote()->transact(RELEASE_INPUT, data, &reply);
     }
 
@@ -1055,6 +1047,7 @@
             audio_session_t session = (audio_session_t)data.readInt32();
             pid_t pid = (pid_t)data.readInt32();
             uid_t uid = (uid_t)data.readInt32();
+            const String16 opPackageName = data.readString16();
             audio_config_base_t config;
             memset(&config, 0, sizeof(audio_config_base_t));
             data.read(&config, sizeof(audio_config_base_t));
@@ -1062,7 +1055,7 @@
             audio_port_handle_t selectedDeviceId = (audio_port_handle_t) data.readInt32();
             audio_port_handle_t portId = (audio_port_handle_t)data.readInt32();
             status_t status = getInputForAttr(&attr, &input, session, pid, uid,
-                                              &config,
+                                              opPackageName, &config,
                                               flags, &selectedDeviceId, &portId);
             reply->writeInt32(status);
             if (status == NO_ERROR) {
@@ -1075,12 +1068,9 @@
 
         case START_INPUT: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
-            audio_io_handle_t input = static_cast <audio_io_handle_t>(data.readInt32());
-            audio_session_t session = static_cast <audio_session_t>(data.readInt32());
-            audio_devices_t device = static_cast <audio_devices_t>(data.readInt32());
-            uid_t uid = static_cast <uid_t>(data.readInt32());
+            audio_port_handle_t portId = static_cast <audio_port_handle_t>(data.readInt32());
             bool silenced = data.readInt32() == 1;
-            status_t status = startInput(input, session, device, uid, &silenced);
+            status_t status = startInput(portId, &silenced);
             reply->writeInt32(static_cast <uint32_t>(status));
             reply->writeInt32(silenced ? 1 : 0);
             return NO_ERROR;
@@ -1088,17 +1078,15 @@
 
         case STOP_INPUT: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
-            audio_io_handle_t input = static_cast <audio_io_handle_t>(data.readInt32());
-            audio_session_t session = static_cast <audio_session_t>(data.readInt32());
-            reply->writeInt32(static_cast <uint32_t>(stopInput(input, session)));
+            audio_port_handle_t portId = static_cast <audio_port_handle_t>(data.readInt32());
+            reply->writeInt32(static_cast <uint32_t>(stopInput(portId)));
             return NO_ERROR;
         } break;
 
         case RELEASE_INPUT: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
-            audio_io_handle_t input = static_cast <audio_io_handle_t>(data.readInt32());
-            audio_session_t session = static_cast <audio_session_t>(data.readInt32());
-            releaseInput(input, session);
+            audio_port_handle_t portId = static_cast <audio_port_handle_t>(data.readInt32());
+            releaseInput(portId);
             return NO_ERROR;
         } break;
 
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 3c8e7bc..22b700d 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -241,20 +241,16 @@
                                     audio_session_t session,
                                     pid_t pid,
                                     uid_t uid,
+                                    const String16& opPackageName,
                                     const audio_config_base_t *config,
                                     audio_input_flags_t flags,
                                     audio_port_handle_t *selectedDeviceId,
                                     audio_port_handle_t *portId);
 
-    static status_t startInput(audio_io_handle_t input,
-                               audio_session_t session,
-                               audio_devices_t device,
-                               uid_t uid,
+    static status_t startInput(audio_port_handle_t portId,
                                bool *silenced);
-    static status_t stopInput(audio_io_handle_t input,
-                              audio_session_t session);
-    static void releaseInput(audio_io_handle_t input,
-                             audio_session_t session);
+    static status_t stopInput(audio_port_handle_t portId);
+    static void releaseInput(audio_port_handle_t portId);
     static status_t initStreamVolume(audio_stream_type_t stream,
                                       int indexMin,
                                       int indexMax);
diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h
index 5338927..949d593 100644
--- a/media/libaudioclient/include/media/IAudioPolicyService.h
+++ b/media/libaudioclient/include/media/IAudioPolicyService.h
@@ -80,19 +80,15 @@
                               audio_session_t session,
                               pid_t pid,
                               uid_t uid,
+                              const String16& opPackageName,
                               const audio_config_base_t *config,
                               audio_input_flags_t flags,
                               audio_port_handle_t *selectedDeviceId,
                               audio_port_handle_t *portId) = 0;
-    virtual status_t startInput(audio_io_handle_t input,
-                                audio_session_t session,
-                                audio_devices_t device,
-                                uid_t uid,
+    virtual status_t startInput(audio_port_handle_t portId,
                                 bool *silenced) = 0;
-    virtual status_t stopInput(audio_io_handle_t input,
-                               audio_session_t session) = 0;
-    virtual void releaseInput(audio_io_handle_t input,
-                              audio_session_t session) = 0;
+    virtual status_t stopInput(audio_port_handle_t portId) = 0;
+    virtual void releaseInput(audio_port_handle_t portId) = 0;
     virtual status_t initStreamVolume(audio_stream_type_t stream,
                                       int indexMin,
                                       int indexMax) = 0;
diff --git a/media/libmedia/include/media/CryptoHal.h b/media/libmedia/include/media/CryptoHal.h
index a5d8b43..ed16f44 100644
--- a/media/libmedia/include/media/CryptoHal.h
+++ b/media/libmedia/include/media/CryptoHal.h
@@ -20,14 +20,16 @@
 
 #include <android/hardware/drm/1.0/ICryptoFactory.h>
 #include <android/hardware/drm/1.0/ICryptoPlugin.h>
+#include <android/hardware/drm/1.1/ICryptoFactory.h>
 
 #include <media/ICrypto.h>
 #include <utils/KeyedVector.h>
 #include <utils/threads.h>
 
-using ::android::hardware::drm::V1_0::ICryptoFactory;
-using ::android::hardware::drm::V1_0::ICryptoPlugin;
-using ::android::hardware::drm::V1_0::SharedBuffer;
+namespace drm = ::android::hardware::drm;
+using drm::V1_0::ICryptoFactory;
+using drm::V1_0::ICryptoPlugin;
+using drm::V1_0::SharedBuffer;
 
 class IMemoryHeap;
 
diff --git a/media/libmedia/include/media/DrmHal.h b/media/libmedia/include/media/DrmHal.h
index ec3a9b3..1c09036 100644
--- a/media/libmedia/include/media/DrmHal.h
+++ b/media/libmedia/include/media/DrmHal.h
@@ -18,10 +18,11 @@
 
 #define DRM_HAL_H_
 
-#include <android/hardware/drm/1.0/IDrmPlugin.h>
-#include <android/hardware/drm/1.1/IDrmPlugin.h>
-#include <android/hardware/drm/1.0/IDrmPluginListener.h>
 #include <android/hardware/drm/1.0/IDrmFactory.h>
+#include <android/hardware/drm/1.0/IDrmPlugin.h>
+#include <android/hardware/drm/1.0/IDrmPluginListener.h>
+#include <android/hardware/drm/1.1/IDrmFactory.h>
+#include <android/hardware/drm/1.1/IDrmPlugin.h>
 
 #include <media/DrmMetrics.h>
 #include <media/IDrm.h>
@@ -63,7 +64,8 @@
 
     virtual status_t destroyPlugin();
 
-    virtual status_t openSession(Vector<uint8_t> &sessionId);
+    virtual status_t openSession(DrmPlugin::SecurityLevel level,
+            Vector<uint8_t> &sessionId);
 
     virtual status_t closeSession(Vector<uint8_t> const &sessionId);
 
@@ -110,8 +112,6 @@
             uint32_t *maxSessions) const;
     virtual status_t getSecurityLevel(Vector<uint8_t> const &sessionId,
             DrmPlugin::SecurityLevel *level) const;
-    virtual status_t setSecurityLevel(Vector<uint8_t> const &sessionId,
-            const DrmPlugin::SecurityLevel& level);
 
     virtual status_t getPropertyString(String8 const &name, String8 &value ) const;
     virtual status_t getPropertyByteArray(String8 const &name,
diff --git a/media/libmedia/include/media/IDrm.h b/media/libmedia/include/media/IDrm.h
index 994cade..c3ae684 100644
--- a/media/libmedia/include/media/IDrm.h
+++ b/media/libmedia/include/media/IDrm.h
@@ -40,7 +40,8 @@
 
     virtual status_t destroyPlugin() = 0;
 
-    virtual status_t openSession(Vector<uint8_t> &sessionId) = 0;
+    virtual status_t openSession(DrmPlugin::SecurityLevel securityLevel,
+            Vector<uint8_t> &sessionId) = 0;
 
     virtual status_t closeSession(Vector<uint8_t> const &sessionId) = 0;
 
@@ -88,8 +89,6 @@
             uint32_t *maxSessions) const = 0;
     virtual status_t getSecurityLevel(Vector<uint8_t> const &sessionId,
             DrmPlugin::SecurityLevel *level) const = 0;
-    virtual status_t setSecurityLevel(Vector<uint8_t> const &sessionId,
-            const DrmPlugin::SecurityLevel& level) = 0;
 
     virtual status_t getPropertyString(String8 const &name, String8 &value) const = 0;
     virtual status_t getPropertyByteArray(String8 const &name,
diff --git a/media/libmediaplayer2/MediaPlayer2Manager.cpp b/media/libmediaplayer2/MediaPlayer2Manager.cpp
index b254456..44df2ac 100644
--- a/media/libmediaplayer2/MediaPlayer2Manager.cpp
+++ b/media/libmediaplayer2/MediaPlayer2Manager.cpp
@@ -580,7 +580,7 @@
         audio_port_handle_t deviceId) {
     sp<MediaPlayer2Interface> listener = mListener.promote();
     if (listener != NULL) {
-        listener->sendEvent(MEDIA2_AUDIO_ROUTING_CHANGED, audioIo, deviceId);
+        listener->sendEvent(0, MEDIA2_AUDIO_ROUTING_CHANGED, audioIo, deviceId);
     } else {
         ALOGW("listener for process %d death is gone", MEDIA2_AUDIO_ROUTING_CHANGED);
     }
@@ -1031,7 +1031,8 @@
 }
 
 void MediaPlayer2Manager::Client::notify(
-        const wp<MediaPlayer2Engine> &listener, int msg, int ext1, int ext2, const Parcel *obj)
+        const wp<MediaPlayer2Engine> &listener, int64_t srcId,
+        int msg, int ext1, int ext2, const Parcel *obj)
 {
     sp<MediaPlayer2Engine> spListener = listener.promote();
     if (spListener == NULL) {
@@ -1063,9 +1064,9 @@
         }
         if (nc != NULL) {
             if (errStartNext == NO_ERROR) {
-                nc->notify(MEDIA2_INFO, MEDIA2_INFO_STARTED_AS_NEXT, 0, obj);
+                nc->notify(srcId, MEDIA2_INFO, MEDIA2_INFO_STARTED_AS_NEXT, 0, obj);
             } else {
-                nc->notify(MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN , 0, obj);
+                nc->notify(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN , 0, obj);
                 ALOGE("gapless:start playback for next track failed, err(%d)", errStartNext);
             }
         }
@@ -1085,8 +1086,9 @@
     }
 
     if (c != NULL) {
-        ALOGV("[%d] notify (%p, %d, %d, %d)", client->mConnId, spListener.get(), msg, ext1, ext2);
-        c->notify(msg, ext1, ext2, obj);
+        ALOGV("[%d] notify (%p, %lld, %d, %d, %d)", client->mConnId, spListener.get(),
+              (long long)srcId, msg, ext1, ext2);
+        c->notify(srcId, msg, ext1, ext2, obj);
     }
 }
 
diff --git a/media/libmediaplayer2/MediaPlayer2Manager.h b/media/libmediaplayer2/MediaPlayer2Manager.h
index fde1381..7e6f0de 100644
--- a/media/libmediaplayer2/MediaPlayer2Manager.h
+++ b/media/libmediaplayer2/MediaPlayer2Manager.h
@@ -276,8 +276,8 @@
 
         virtual status_t        setDataSource(const sp<DataSourceDesc> &dsd);
 
-        static  void            notify(const wp<MediaPlayer2Engine> &listener, int msg,
-                                       int ext1, int ext2, const Parcel *obj);
+        static  void            notify(const wp<MediaPlayer2Engine> &listener, int64_t srcId,
+                                       int msg, int ext1, int ext2, const Parcel *obj);
 
                 pid_t           pid() const { return mPid; }
         virtual status_t        dump(int fd, const Vector<String16>& args);
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2EngineClient.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2EngineClient.h
index 22df095..0b066aa 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2EngineClient.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2EngineClient.h
@@ -25,7 +25,7 @@
 class MediaPlayer2EngineClient: public RefBase
 {
 public:
-    virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) = 0;
+    virtual void notify(int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj) = 0;
 };
 
 }; // namespace android
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
index 1de4348..b1cdf96 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
@@ -64,7 +64,7 @@
 public:
     // callback mechanism for passing messages to MediaPlayer2 object
     typedef void (*NotifyCallback)(const wp<MediaPlayer2Engine> &listener,
-            int msg, int ext1, int ext2, const Parcel *obj);
+            int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj);
 
     // AudioSink: abstraction layer for audio output
     class AudioSink : public RefBase {
@@ -240,7 +240,7 @@
         mClient = client; mNotify = notifyFunc;
     }
 
-    void        sendEvent(int msg, int ext1=0, int ext2=0,
+    void        sendEvent(int64_t srcId, int msg, int ext1=0, int ext2=0,
                           const Parcel *obj=NULL) {
         NotifyCallback notifyCB;
         wp<MediaPlayer2Engine> client;
@@ -250,7 +250,7 @@
             client = mClient;
         }
 
-        if (notifyCB) notifyCB(client, msg, ext1, ext2, obj);
+        if (notifyCB) notifyCB(client, srcId, msg, ext1, ext2, obj);
     }
 
     virtual status_t dump(int /* fd */, const Vector<String16>& /* args */) const {
diff --git a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
index 8e188eb..e9d6f84 100644
--- a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
+++ b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
@@ -194,7 +194,7 @@
 class MediaPlayer2Listener: virtual public RefBase
 {
 public:
-    virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) = 0;
+    virtual void notify(int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj) = 0;
 };
 
 class MediaPlayer2 : public MediaPlayer2EngineClient
@@ -204,6 +204,7 @@
     ~MediaPlayer2();
             void            disconnect();
 
+            status_t        getSrcId(int64_t *srcId);
             status_t        setDataSource(const sp<DataSourceDesc> &dsd);
             status_t        setVideoSurfaceTexture(const sp<ANativeWindowWrapper>& nww);
             status_t        setListener(const sp<MediaPlayer2Listener>& listener);
@@ -235,7 +236,8 @@
             status_t        setLooping(int loop);
             bool            isLooping();
             status_t        setVolume(float leftVolume, float rightVolume);
-            void            notify(int msg, int ext1, int ext2, const Parcel *obj = NULL);
+            void            notify(int64_t srcId, int msg, int ext1, int ext2,
+                                   const Parcel *obj = NULL);
             status_t        invoke(const Parcel& request, Parcel *reply);
             status_t        setMetadataFilter(const Parcel& filter);
             status_t        getMetadata(bool update_only, bool apply_filter, Parcel *metadata);
@@ -260,11 +262,12 @@
             status_t        seekTo_l(int msec, MediaPlayer2SeekMode mode);
             status_t        prepareAsync_l();
             status_t        getDuration_l(int *msec);
-            status_t        attachNewPlayer(const sp<MediaPlayer2Engine>& player);
+            status_t        attachNewPlayer(const sp<MediaPlayer2Engine>& player, long srcId);
             status_t        reset_l();
             status_t        checkStateForKeySet_l(int key);
 
     sp<MediaPlayer2Engine>      mPlayer;
+    int64_t                     mSrcId;
     thread_id_t                 mLockThreadId;
     Mutex                       mLock;
     Mutex                       mNotifyLock;
diff --git a/media/libmediaplayer2/mediaplayer2.cpp b/media/libmediaplayer2/mediaplayer2.cpp
index b858783..ab30273 100644
--- a/media/libmediaplayer2/mediaplayer2.cpp
+++ b/media/libmediaplayer2/mediaplayer2.cpp
@@ -53,6 +53,7 @@
 MediaPlayer2::MediaPlayer2()
 {
     ALOGV("constructor");
+    mSrcId = 0;
     mListener = NULL;
     mCookie = NULL;
     mStreamType = AUDIO_STREAM_MUSIC;
@@ -118,8 +119,17 @@
     return NO_ERROR;
 }
 
+status_t MediaPlayer2::getSrcId(int64_t *srcId) {
+    if (srcId == NULL) {
+        return BAD_VALUE;
+    }
 
-status_t MediaPlayer2::attachNewPlayer(const sp<MediaPlayer2Engine>& player)
+    Mutex::Autolock _l(mLock);
+    *srcId = mSrcId;
+    return OK;
+}
+
+status_t MediaPlayer2::attachNewPlayer(const sp<MediaPlayer2Engine>& player, long srcId)
 {
     status_t err = UNKNOWN_ERROR;
     sp<MediaPlayer2Engine> p;
@@ -135,6 +145,7 @@
         clear_l();
         p = mPlayer;
         mPlayer = player;
+        mSrcId = srcId;
         if (player != 0) {
             mCurrentState = MEDIA_PLAYER2_INITIALIZED;
             err = NO_ERROR;
@@ -161,7 +172,7 @@
     if (NO_ERROR != player->setDataSource(dsd)) {
         player.clear();
     }
-    err = attachNewPlayer(player);
+    err = attachNewPlayer(player, dsd->mId);
     return err;
 }
 
@@ -763,9 +774,10 @@
     return INVALID_OPERATION;
 }
 
-void MediaPlayer2::notify(int msg, int ext1, int ext2, const Parcel *obj)
+void MediaPlayer2::notify(int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj)
 {
-    ALOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
+    ALOGV("message received srcId=%lld, msg=%d, ext1=%d, ext2=%d",
+          (long long)srcId, msg, ext1, ext2);
     bool send = true;
     bool locked = false;
 
@@ -784,7 +796,8 @@
 
     // Allows calls from JNI in idle state to notify errors
     if (!(msg == MEDIA2_ERROR && mCurrentState == MEDIA_PLAYER2_IDLE) && mPlayer == 0) {
-        ALOGV("notify(%d, %d, %d) callback on disconnected mediaplayer", msg, ext1, ext2);
+        ALOGV("notify(%lld, %d, %d, %d) callback on disconnected mediaplayer",
+              (long long)srcId, msg, ext1, ext2);
         if (locked) mLock.unlock();   // release the lock when done.
         return;
     }
@@ -803,7 +816,8 @@
         }
         break;
     case MEDIA2_DRM_INFO:
-        ALOGV("MediaPlayer2::notify() MEDIA2_DRM_INFO(%d, %d, %d, %p)", msg, ext1, ext2, obj);
+        ALOGV("MediaPlayer2::notify() MEDIA2_DRM_INFO(%lld, %d, %d, %d, %p)",
+              (long long)srcId, msg, ext1, ext2, obj);
         break;
     case MEDIA2_PLAYBACK_COMPLETE:
         ALOGV("playback complete");
@@ -882,7 +896,7 @@
     if ((listener != 0) && send) {
         Mutex::Autolock _l(mNotifyLock);
         ALOGV("callback application");
-        listener->notify(msg, ext1, ext2, obj);
+        listener->notify(srcId, msg, ext1, ext2, obj);
         ALOGV("back from callback");
     }
 }
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
index ea9d270..462a904 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
@@ -314,6 +314,7 @@
                 if (err == OK) {
                     *source = genericSource;
                 } else {
+                    *source = NULL;
                     ALOGE("Failed to create NuPlayer2Source!");
                 }
 
@@ -364,7 +365,7 @@
 
         default:
             err = BAD_TYPE;
-            source = NULL;
+            *source = NULL;
             *dataSourceType = DATA_SOURCE_TYPE_NONE;
             ALOGE("invalid data source type!");
             break;
@@ -376,13 +377,22 @@
 void NuPlayer2::setDataSourceAsync(const sp<DataSourceDesc> &dsd) {
     DATA_SOURCE_TYPE dataSourceType;
     sp<Source> source;
-    status_t err = createNuPlayer2Source(dsd, &source, &dataSourceType);
+    createNuPlayer2Source(dsd, &source, &dataSourceType);
 
+    // TODO: currently NuPlayer2Driver makes blocking call to setDataSourceAsync
+    // and expects notifySetDataSourceCompleted regardless of success or failure.
+    // This will be changed since setDataSource should be asynchronous at JAVA level.
+    // When it succeeds, app will get onInfo notification. Otherwise, onError
+    // will be called.
+    /*
     if (err != OK) {
-        notifyListener(MEDIA2_ERROR, MEDIA2_ERROR_FAILED_TO_SET_DATA_SOURCE, err);
+        notifyListener(dsd->mId, MEDIA2_ERROR, MEDIA2_ERROR_FAILED_TO_SET_DATA_SOURCE, err);
         return;
     }
 
+    // Now, source != NULL.
+    */
+
     mDataSourceType = dataSourceType;
 
     sp<AMessage> msg = new AMessage(kWhatSetDataSource, this);
@@ -394,13 +404,17 @@
 void NuPlayer2::prepareNextDataSourceAsync(const sp<DataSourceDesc> &dsd) {
     DATA_SOURCE_TYPE dataSourceType;
     sp<Source> source;
-    status_t err = createNuPlayer2Source(dsd, &source, &dataSourceType);
+    createNuPlayer2Source(dsd, &source, &dataSourceType);
 
+    /*
     if (err != OK) {
-        notifyListener(MEDIA2_ERROR, MEDIA2_ERROR_FAILED_TO_SET_DATA_SOURCE, err);
+        notifyListener(dsd->mId, MEDIA2_ERROR, MEDIA2_ERROR_FAILED_TO_SET_DATA_SOURCE, err);
         return;
     }
 
+    // Now, source != NULL.
+    */
+
     mNextDataSourceType = dataSourceType;
 
     sp<AMessage> msg = new AMessage(kWhatPrepareNextDataSource, this);
@@ -627,12 +641,13 @@
                 mSource = static_cast<Source *>(obj.get());
             } else {
                 err = UNKNOWN_ERROR;
+                ALOGE("kWhatSetDataSource, source should not be NULL");
             }
 
             CHECK(mDriver != NULL);
             sp<NuPlayer2Driver> driver = mDriver.promote();
             if (driver != NULL) {
-                driver->notifySetDataSourceCompleted(err);
+                driver->notifySetDataSourceCompleted(mSrcId, err);
             }
             break;
         }
@@ -831,7 +846,7 @@
             if (mDriver != NULL && mSource->getDuration(&durationUs) == OK) {
                 sp<NuPlayer2Driver> driver = mDriver.promote();
                 if (driver != NULL) {
-                    driver->notifyDuration(durationUs);
+                    driver->notifyDuration(mSrcId, durationUs);
                 }
             }
 
@@ -921,6 +936,7 @@
                 onStart();
             }
             mPausedByClient = false;
+            notifyListener(mSrcId, MEDIA2_STARTED, 0, 0);
             break;
         }
 
@@ -960,6 +976,7 @@
             if (err == OK) {
                 if (rate.mSpeed == 0.f) {
                     onPause();
+                    notifyListener(mSrcId, MEDIA2_PAUSED, 0, 0);
                     mPausedByClient = true;
                     // save all other settings (using non-paused speed)
                     // so we can restore them on start
@@ -1114,9 +1131,9 @@
                     // video tracks found) and we just ran out of input data.
 
                     if (err == ERROR_END_OF_STREAM) {
-                        notifyListener(MEDIA2_PLAYBACK_COMPLETE, 0, 0);
+                        notifyListener(mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
                     } else {
-                        notifyListener(MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+                        notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
                     }
                 }
                 break;
@@ -1201,7 +1218,7 @@
                         mSource->getFormat(false /* audio */);
 
                 setVideoScalingMode(mVideoScalingMode);
-                updateVideoSize(inputFormat, format);
+                updateVideoSize(mSrcId, inputFormat, format);
             } else if (what == DecoderBase::kWhatShutdownCompleted) {
                 ALOGV("%s shutdown completed", audio ? "audio" : "video");
                 if (audio) {
@@ -1275,10 +1292,10 @@
                                 || mVideoDecoder == NULL) {
                             // When both audio and video have error, or this stream has only audio
                             // which has error, notify client of error.
-                            notifyListener(MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+                            notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
                         } else {
                             // Only audio track has error. Video track could be still good to play.
-                            notifyListener(MEDIA2_INFO, MEDIA2_INFO_PLAY_AUDIO_ERROR, err);
+                            notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_PLAY_AUDIO_ERROR, err);
                         }
                         mAudioDecoderError = true;
                     } else {
@@ -1286,10 +1303,10 @@
                                 || mAudioSink == NULL || mAudioDecoder == NULL) {
                             // When both audio and video have error, or this stream has only video
                             // which has error, notify client of error.
-                            notifyListener(MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+                            notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
                         } else {
                             // Only video track has error. Audio track could be still good to play.
-                            notifyListener(MEDIA2_INFO, MEDIA2_INFO_PLAY_VIDEO_ERROR, err);
+                            notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_PLAY_VIDEO_ERROR, err);
                         }
                         mVideoDecoderError = true;
                     }
@@ -1339,12 +1356,12 @@
                          audio ? "audio" : "video", finalResult);
 
                     notifyListener(
-                            MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, finalResult);
+                            mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, finalResult);
                 }
 
                 if ((mAudioEOS || mAudioDecoder == NULL)
                         && (mVideoEOS || mVideoDecoder == NULL)) {
-                    notifyListener(MEDIA2_PLAYBACK_COMPLETE, 0, 0);
+                    notifyListener(mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
                 }
             } else if (what == Renderer::kWhatFlushComplete) {
                 int32_t audio;
@@ -1365,10 +1382,10 @@
                 handleFlushComplete(audio, false /* isDecoder */);
                 finishFlushIfPossible();
             } else if (what == Renderer::kWhatVideoRenderingStart) {
-                notifyListener(MEDIA2_INFO, MEDIA2_INFO_RENDERING_START, 0);
+                notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_RENDERING_START, 0);
             } else if (what == Renderer::kWhatMediaRenderingStart) {
                 ALOGV("media rendering started");
-                notifyListener(MEDIA2_STARTED, 0, 0);
+                notifyListener(mSrcId, MEDIA2_STARTED, 0, 0);
             } else if (what == Renderer::kWhatAudioTearDown) {
                 int32_t reason;
                 CHECK(msg->findInt32("reason", &reason));
@@ -1421,7 +1438,7 @@
             int64_t timerUs;
             CHECK(msg->findInt64("timerUs", &timerUs));
 
-            notifyListener(MEDIA2_NOTIFY_TIME, timerUs, 0);
+            notifyListener(mSrcId, MEDIA2_NOTIFY_TIME, timerUs, 0);
             break;
         }
 
@@ -1438,22 +1455,23 @@
                     (long long)seekTimeUs, mode, needNotify);
 
             if (!mStarted) {
-                // Seek before the player is started. In order to preview video,
-                // need to start the player and pause it. This branch is called
-                // only once if needed. After the player is started, any seek
-                // operation will go through normal path.
-                // Audio-only cases are handled separately.
-                onStart(seekTimeUs, (MediaPlayer2SeekMode)mode);
-                if (mStarted) {
-                    onPause();
-                    mPausedByClient = true;
+                if (!mSourceStarted) {
+                    mSourceStarted = true;
+                    mSource->start();
                 }
+                if (seekTimeUs > 0) {
+                    performSeek(seekTimeUs, (MediaPlayer2SeekMode)mode);
+                }
+
                 if (needNotify) {
-                    notifyDriverSeekComplete();
+                    notifyDriverSeekComplete(mSrcId);
                 }
                 break;
             }
 
+            // seeks can take a while, so we essentially paused
+            notifyListener(mSrcId, MEDIA2_PAUSED, 0, 0);
+
             mDeferredActions.push_back(
                     new FlushDecoderAction(FLUSH_CMD_FLUSH /* audio */,
                                            FLUSH_CMD_FLUSH /* video */));
@@ -1474,6 +1492,7 @@
         case kWhatPause:
         {
             onPause();
+            notifyListener(mSrcId, MEDIA2_PAUSED, 0, 0);
             mPausedByClient = true;
             break;
         }
@@ -1545,19 +1564,13 @@
     startPlaybackTimer("onresume");
 }
 
-void NuPlayer2::onStart(int64_t startPositionUs, MediaPlayer2SeekMode mode) {
+void NuPlayer2::onStart() {
     ALOGV("onStart: mCrypto: %p", mCrypto.get());
 
     if (!mSourceStarted) {
         mSourceStarted = true;
         mSource->start();
     }
-    if (startPositionUs > 0) {
-        performSeek(startPositionUs, mode);
-        if (mSource->getFormat(false /* audio */) == NULL) {
-            return;
-        }
-    }
 
     mOffloadAudio = false;
     mAudioEOS = false;
@@ -1577,7 +1590,7 @@
         ALOGE("no metadata for either audio or video source");
         mSource->stop();
         mSourceStarted = false;
-        notifyListener(MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, ERROR_MALFORMED);
+        notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, ERROR_MALFORMED);
         return;
     }
     ALOGV_IF(!hasAudio, "no metadata for audio source");  // video only stream
@@ -1616,7 +1629,7 @@
     if (err != OK) {
         mSource->stop();
         mSourceStarted = false;
-        notifyListener(MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+        notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
         return;
     }
 
@@ -1658,7 +1671,7 @@
             ALOGV("stopPlaybackTimer()  log  %20" PRId64 "", played);
 
             if (played > 0) {
-                driver->notifyMorePlayingTimeUs((played+500)/1000);
+                driver->notifyMorePlayingTimeUs(mSrcId, (played+500)/1000);
             }
         }
         mLastStartedPlayingTimeNs = 0;
@@ -1686,9 +1699,9 @@
             ALOGV("stopRebufferingTimer()  log  %20" PRId64 "", rebuffered);
 
             if (rebuffered > 0) {
-                driver->notifyMoreRebufferingTimeUs((rebuffered+500)/1000);
+                driver->notifyMoreRebufferingTimeUs(mSrcId, (rebuffered+500)/1000);
                 if (exitingPlayback) {
-                    driver->notifyRebufferingWhenExit(true);
+                    driver->notifyRebufferingWhenExit(mSrcId, true);
                 }
             }
         }
@@ -2005,11 +2018,12 @@
 }
 
 void NuPlayer2::updateVideoSize(
+        int64_t srcId,
         const sp<AMessage> &inputFormat,
         const sp<AMessage> &outputFormat) {
     if (inputFormat == NULL) {
         ALOGW("Unknown video size, reporting 0x0!");
-        notifyListener(MEDIA2_SET_VIDEO_SIZE, 0, 0);
+        notifyListener(srcId, MEDIA2_SET_VIDEO_SIZE, 0, 0);
         return;
     }
     int32_t err = OK;
@@ -2088,12 +2102,13 @@
     }
 
     notifyListener(
+            srcId,
             MEDIA2_SET_VIDEO_SIZE,
             displayWidth,
             displayHeight);
 }
 
-void NuPlayer2::notifyListener(int msg, int ext1, int ext2, const Parcel *in) {
+void NuPlayer2::notifyListener(int64_t srcId, int msg, int ext1, int ext2, const Parcel *in) {
     if (mDriver == NULL) {
         return;
     }
@@ -2104,7 +2119,7 @@
         return;
     }
 
-    driver->notifyListener(msg, ext1, ext2, in);
+    driver->notifyListener(srcId, msg, ext1, ext2, in);
 }
 
 void NuPlayer2::flushDecoder(bool audio, bool needShutdown) {
@@ -2369,7 +2384,7 @@
     if (mDriver != NULL) {
         sp<NuPlayer2Driver> driver = mDriver.promote();
         if (driver != NULL) {
-            driver->notifyResetComplete();
+            driver->notifyResetComplete(mSrcId);
         }
     }
 
@@ -2411,7 +2426,7 @@
     if (mDriver != NULL) {
         sp<NuPlayer2Driver> driver = mDriver.promote();
         if (driver != NULL) {
-            driver->notifySetSurfaceComplete();
+            driver->notifySetSurfaceComplete(mSrcId);
         }
     }
 }
@@ -2443,15 +2458,15 @@
 void NuPlayer2::finishResume() {
     if (mResumePending) {
         mResumePending = false;
-        notifyDriverSeekComplete();
+        notifyDriverSeekComplete(mSrcId);
     }
 }
 
-void NuPlayer2::notifyDriverSeekComplete() {
+void NuPlayer2::notifyDriverSeekComplete(int64_t srcId) {
     if (mDriver != NULL) {
         sp<NuPlayer2Driver> driver = mDriver.promote();
         if (driver != NULL) {
-            driver->notifySeekComplete();
+            driver->notifySeekComplete(srcId);
         }
     }
 }
@@ -2460,7 +2475,8 @@
     int32_t what;
     CHECK(msg->findInt32("what", &what));
 
-    // TODO: tell this is for mSource or mNextSource.
+    int64_t srcId;
+    CHECK(msg->findInt64("srcId", &srcId));
     switch (what) {
         case Source::kWhatPrepared:
         {
@@ -2491,9 +2507,9 @@
                 // the app received the "prepare complete" callback.
                 int64_t durationUs;
                 if (mSource->getDuration(&durationUs) == OK) {
-                    driver->notifyDuration(durationUs);
+                    driver->notifyDuration(srcId, durationUs);
                 }
-                driver->notifyPrepareCompleted(err);
+                driver->notifyPrepareCompleted(srcId, err);
             }
 
             break;
@@ -2510,7 +2526,7 @@
             ALOGV("onSourceNotify() kWhatDrmInfo MEDIA2_DRM_INFO drmInfo: %p  parcel size: %zu",
                     drmInfo.get(), parcel.dataSize());
 
-            notifyListener(MEDIA2_DRM_INFO, 0 /* ext1 */, 0 /* ext2 */, &parcel);
+            notifyListener(srcId, MEDIA2_DRM_INFO, 0 /* ext1 */, 0 /* ext2 */, &parcel);
 
             break;
         }
@@ -2537,9 +2553,9 @@
 
                 if ((flags & NuPlayer2::Source::FLAG_CAN_SEEK) == 0) {
                     driver->notifyListener(
-                            MEDIA2_INFO, MEDIA2_INFO_NOT_SEEKABLE, 0);
+                            srcId, MEDIA2_INFO, MEDIA2_INFO_NOT_SEEKABLE, 0);
                 }
-                driver->notifyFlagsChanged(flags);
+                driver->notifyFlagsChanged(srcId, flags);
             }
 
             if ((mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
@@ -2560,7 +2576,7 @@
             sp<AMessage> format;
             CHECK(msg->findMessage("format", &format));
 
-            updateVideoSize(format);
+            updateVideoSize(srcId, format);
             break;
         }
 
@@ -2569,7 +2585,7 @@
             int32_t percentage;
             CHECK(msg->findInt32("percentage", &percentage));
 
-            notifyListener(MEDIA2_BUFFERING_UPDATE, percentage, 0);
+            notifyListener(srcId, MEDIA2_BUFFERING_UPDATE, percentage, 0);
             break;
         }
 
@@ -2583,7 +2599,7 @@
                 mPausedForBuffering = true;
                 onPause();
             }
-            notifyListener(MEDIA2_INFO, MEDIA2_INFO_BUFFERING_START, 0);
+            notifyListener(srcId, MEDIA2_INFO, MEDIA2_INFO_BUFFERING_START, 0);
             break;
         }
 
@@ -2601,7 +2617,7 @@
                     onResume();
                 }
             }
-            notifyListener(MEDIA2_INFO, MEDIA2_INFO_BUFFERING_END, 0);
+            notifyListener(srcId, MEDIA2_INFO, MEDIA2_INFO_BUFFERING_END, 0);
             break;
         }
 
@@ -2610,7 +2626,7 @@
             int32_t kbps;
             CHECK(msg->findInt32("bandwidth", &kbps));
 
-            notifyListener(MEDIA2_INFO, MEDIA2_INFO_NETWORK_BANDWIDTH, kbps);
+            notifyListener(srcId, MEDIA2_INFO, MEDIA2_INFO_NETWORK_BANDWIDTH, kbps);
             break;
         }
 
@@ -2627,7 +2643,7 @@
         {
             sp<ABuffer> buffer;
             if (!msg->findBuffer("buffer", &buffer)) {
-                notifyListener(MEDIA2_INFO, MEDIA2_INFO_METADATA_UPDATE, 0);
+                notifyListener(srcId, MEDIA2_INFO, MEDIA2_INFO_METADATA_UPDATE, 0);
             } else {
                 sendTimedMetaData(buffer);
             }
@@ -2682,7 +2698,7 @@
 
         case Source::kWhatDrmNoLicense:
         {
-            notifyListener(MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
+            notifyListener(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
             break;
         }
 
@@ -2712,7 +2728,7 @@
 
         case NuPlayer2::CCDecoder::kWhatTrackAdded:
         {
-            notifyListener(MEDIA2_INFO, MEDIA2_INFO_METADATA_UPDATE, 0);
+            notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_METADATA_UPDATE, 0);
 
             break;
         }
@@ -2739,7 +2755,7 @@
     in.writeInt32(buffer->size());
     in.write(buffer->data(), buffer->size());
 
-    notifyListener(MEDIA2_SUBTITLE_DATA, 0, 0, &in);
+    notifyListener(mSrcId, MEDIA2_SUBTITLE_DATA, 0, 0, &in);
 }
 
 void NuPlayer2::sendTimedMetaData(const sp<ABuffer> &buffer) {
@@ -2752,7 +2768,7 @@
     in.writeInt32(buffer->size());
     in.write(buffer->data(), buffer->size());
 
-    notifyListener(MEDIA2_META_DATA, 0, 0, &in);
+    notifyListener(mSrcId, MEDIA2_META_DATA, 0, 0, &in);
 }
 
 void NuPlayer2::sendTimedTextData(const sp<ABuffer> &buffer) {
@@ -2782,9 +2798,9 @@
     }
 
     if ((parcel.dataSize() > 0)) {
-        notifyListener(MEDIA2_TIMED_TEXT, 0, 0, &parcel);
+        notifyListener(mSrcId, MEDIA2_TIMED_TEXT, 0, 0, &parcel);
     } else {  // send an empty timed text
-        notifyListener(MEDIA2_TIMED_TEXT, 0, 0);
+        notifyListener(mSrcId, MEDIA2_TIMED_TEXT, 0, 0);
     }
 }
 
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.h b/media/libmediaplayer2/nuplayer2/NuPlayer2.h
index bf55b65..e7b774c 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.h
@@ -284,17 +284,16 @@
             bool audio, sp<DecoderBase> *decoder, bool checkAudioModeChange = true);
 
     void updateVideoSize(
+            int64_t srcId,
             const sp<AMessage> &inputFormat,
             const sp<AMessage> &outputFormat = NULL);
 
-    void notifyListener(int msg, int ext1, int ext2, const Parcel *in = NULL);
+    void notifyListener(int64_t srcId, int msg, int ext1, int ext2, const Parcel *in = NULL);
 
     void handleFlushComplete(bool audio, bool isDecoder);
     void finishFlushIfPossible();
 
-    void onStart(
-            int64_t startPositionUs = -1,
-            MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC);
+    void onStart();
     void onResume();
     void onPause();
 
@@ -303,7 +302,7 @@
     void flushDecoder(bool audio, bool needShutdown);
 
     void finishResume();
-    void notifyDriverSeekComplete();
+    void notifyDriverSeekComplete(int64_t srcId);
 
     void postScanSources();
 
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
index 607d406..60a07a3 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
@@ -25,6 +25,7 @@
 #include "NuPlayer2.h"
 #include "NuPlayer2Source.h"
 
+#include <media/DataSourceDesc.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AUtils.h>
@@ -108,6 +109,7 @@
     : mState(STATE_IDLE),
       mIsAsyncPrepare(false),
       mAsyncResult(UNKNOWN_ERROR),
+      mSrcId(0),
       mSetSurfaceInProgress(false),
       mDurationUs(-1),
       mPositionUs(-1),
@@ -179,6 +181,7 @@
         return INVALID_OPERATION;
     }
 
+    mSrcId = dsd->mId;
     mState = STATE_SET_DATASOURCE_PENDING;
 
     mPlayer->setDataSourceAsync(dsd);
@@ -361,7 +364,7 @@
 
         case STATE_PAUSED:
             mState = STATE_STOPPED;
-            notifyListener_l(MEDIA2_STOPPED);
+            //notifyListener_l(MEDIA2_STOPPED);
             break;
 
         case STATE_PREPARED:
@@ -396,7 +399,6 @@
 
         case STATE_RUNNING:
             mState = STATE_PAUSED;
-            notifyListener_l(MEDIA2_PAUSED);
             mPlayer->pause();
             break;
 
@@ -420,7 +422,6 @@
         Mutex::Autolock autoLock(mLock);
         if (rate.mSpeed == 0.f && mState == STATE_RUNNING) {
             mState = STATE_PAUSED;
-            notifyListener_l(MEDIA2_PAUSED);
         } else if (rate.mSpeed != 0.f
                 && (mState == STATE_PAUSED
                     || mState == STATE_STOPPED_AND_PREPARED
@@ -457,8 +458,6 @@
         {
             mAtEOS = false;
             mSeekInProgress = true;
-            // seeks can take a while, so we essentially paused
-            notifyListener_l(MEDIA2_PAUSED);
             mPlayer->seekToAsync(seekTimeUs, mode, true /* needNotify */);
             break;
         }
@@ -629,7 +628,7 @@
         {
             CHECK(mIsAsyncPrepare);
 
-            notifyListener_l(MEDIA2_PREPARED);
+            notifyListener_l(mSrcId, MEDIA2_PREPARED);
             break;
         }
 
@@ -638,7 +637,7 @@
     }
 
     if (mState != STATE_STOPPED) {
-        notifyListener_l(MEDIA2_STOPPED);
+        // notifyListener_l(MEDIA2_STOPPED);
     }
 
     mState = STATE_RESET_IN_PROGRESS;
@@ -772,7 +771,7 @@
     return OK;
 }
 
-void NuPlayer2Driver::notifyResetComplete() {
+void NuPlayer2Driver::notifyResetComplete(int64_t /* srcId */) {
     ALOGD("notifyResetComplete(%p)", this);
     Mutex::Autolock autoLock(mLock);
 
@@ -781,7 +780,7 @@
     mCondition.broadcast();
 }
 
-void NuPlayer2Driver::notifySetSurfaceComplete() {
+void NuPlayer2Driver::notifySetSurfaceComplete(int64_t /* srcId */) {
     ALOGV("notifySetSurfaceComplete(%p)", this);
     Mutex::Autolock autoLock(mLock);
 
@@ -791,35 +790,35 @@
     mCondition.broadcast();
 }
 
-void NuPlayer2Driver::notifyDuration(int64_t durationUs) {
+void NuPlayer2Driver::notifyDuration(int64_t /* srcId */, int64_t durationUs) {
     Mutex::Autolock autoLock(mLock);
     mDurationUs = durationUs;
 }
 
-void NuPlayer2Driver::notifyMorePlayingTimeUs(int64_t playingUs) {
+void NuPlayer2Driver::notifyMorePlayingTimeUs(int64_t /* srcId */, int64_t playingUs) {
     Mutex::Autolock autoLock(mLock);
     mPlayingTimeUs += playingUs;
 }
 
-void NuPlayer2Driver::notifyMoreRebufferingTimeUs(int64_t rebufferingUs) {
+void NuPlayer2Driver::notifyMoreRebufferingTimeUs(int64_t /* srcId */, int64_t rebufferingUs) {
     Mutex::Autolock autoLock(mLock);
     mRebufferingTimeUs += rebufferingUs;
     mRebufferingEvents++;
 }
 
-void NuPlayer2Driver::notifyRebufferingWhenExit(bool status) {
+void NuPlayer2Driver::notifyRebufferingWhenExit(int64_t /* srcId */, bool status) {
     Mutex::Autolock autoLock(mLock);
     mRebufferingAtExit = status;
 }
 
-void NuPlayer2Driver::notifySeekComplete() {
+void NuPlayer2Driver::notifySeekComplete(int64_t srcId) {
     ALOGV("notifySeekComplete(%p)", this);
     Mutex::Autolock autoLock(mLock);
     mSeekInProgress = false;
-    notifySeekComplete_l();
+    notifySeekComplete_l(srcId);
 }
 
-void NuPlayer2Driver::notifySeekComplete_l() {
+void NuPlayer2Driver::notifySeekComplete_l(int64_t srcId) {
     bool wasSeeking = true;
     if (mState == STATE_STOPPED_AND_PREPARING) {
         wasSeeking = false;
@@ -833,7 +832,7 @@
         // no need to notify listener
         return;
     }
-    notifyListener_l(wasSeeking ? MEDIA2_SEEK_COMPLETE : MEDIA2_PREPARED);
+    notifyListener_l(srcId, wasSeeking ? MEDIA2_SEEK_COMPLETE : MEDIA2_PREPARED);
 }
 
 status_t NuPlayer2Driver::dump(
@@ -916,9 +915,11 @@
 void NuPlayer2Driver::onMessageReceived(const sp<AMessage> &msg) {
     switch (msg->what()) {
         case kWhatNotifyListener: {
+            int64_t srcId;
             int32_t msgId;
             int32_t ext1 = 0;
             int32_t ext2 = 0;
+            CHECK(msg->findInt64("srcId", &srcId));
             CHECK(msg->findInt32("messageId", &msgId));
             msg->findInt32("ext1", &ext1);
             msg->findInt32("ext2", &ext2);
@@ -927,7 +928,7 @@
             if (msg->findObject("parcel", &obj) && obj != NULL) {
                 in = static_cast<ParcelWrapper *>(obj.get());
             }
-            sendEvent(msgId, ext1, ext2, (in == NULL ? NULL : in->getParcel()));
+            sendEvent(srcId, msgId, ext1, ext2, (in == NULL ? NULL : in->getParcel()));
             break;
         }
         default:
@@ -936,15 +937,16 @@
 }
 
 void NuPlayer2Driver::notifyListener(
-        int msg, int ext1, int ext2, const Parcel *in) {
+        int64_t srcId, int msg, int ext1, int ext2, const Parcel *in) {
     Mutex::Autolock autoLock(mLock);
-    notifyListener_l(msg, ext1, ext2, in);
+    notifyListener_l(srcId, msg, ext1, ext2, in);
 }
 
 void NuPlayer2Driver::notifyListener_l(
-        int msg, int ext1, int ext2, const Parcel *in) {
-    ALOGD("notifyListener_l(%p), (%d, %d, %d, %d), loop setting(%d, %d)",
-            this, msg, ext1, ext2, (in == NULL ? -1 : (int)in->dataSize()), mAutoLoop, mLooping);
+        int64_t srcId, int msg, int ext1, int ext2, const Parcel *in) {
+    ALOGD("notifyListener_l(%p), (%lld, %d, %d, %d, %d), loop setting(%d, %d)",
+            this, (long long)srcId, msg, ext1, ext2,
+            (in == NULL ? -1 : (int)in->dataSize()), mAutoLoop, mLooping);
     switch (msg) {
         case MEDIA2_PLAYBACK_COMPLETE:
         {
@@ -1000,6 +1002,7 @@
     }
 
     sp<AMessage> notify = new AMessage(kWhatNotifyListener, this);
+    notify->setInt64("srcId", srcId);
     notify->setInt32("messageId", msg);
     notify->setInt32("ext1", ext1);
     notify->setInt32("ext2", ext2);
@@ -1007,7 +1010,7 @@
     notify->post();
 }
 
-void NuPlayer2Driver::notifySetDataSourceCompleted(status_t err) {
+void NuPlayer2Driver::notifySetDataSourceCompleted(int64_t /* srcId */, status_t err) {
     Mutex::Autolock autoLock(mLock);
 
     CHECK_EQ(mState, STATE_SET_DATASOURCE_PENDING);
@@ -1017,7 +1020,7 @@
     mCondition.broadcast();
 }
 
-void NuPlayer2Driver::notifyPrepareCompleted(status_t err) {
+void NuPlayer2Driver::notifyPrepareCompleted(int64_t srcId, status_t err) {
     ALOGV("notifyPrepareCompleted %d", err);
 
     Mutex::Autolock autoLock(mLock);
@@ -1039,12 +1042,12 @@
         // in response, NuPlayer2Driver has the right state
         mState = STATE_PREPARED;
         if (mIsAsyncPrepare) {
-            notifyListener_l(MEDIA2_PREPARED);
+            notifyListener_l(srcId, MEDIA2_PREPARED);
         }
     } else {
         mState = STATE_UNPREPARED;
         if (mIsAsyncPrepare) {
-            notifyListener_l(MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+            notifyListener_l(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
         }
     }
 
@@ -1058,7 +1061,7 @@
     mCondition.broadcast();
 }
 
-void NuPlayer2Driver::notifyFlagsChanged(uint32_t flags) {
+void NuPlayer2Driver::notifyFlagsChanged(int64_t /* srcId */, uint32_t flags) {
     Mutex::Autolock autoLock(mLock);
 
     mPlayerFlags = flags;
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h
index 087d2c2..4c57cfd 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h
@@ -67,18 +67,19 @@
 
     virtual void onMessageReceived(const sp<AMessage> &msg) override;
 
-    void notifySetDataSourceCompleted(status_t err);
-    void notifyPrepareCompleted(status_t err);
-    void notifyResetComplete();
-    void notifySetSurfaceComplete();
-    void notifyDuration(int64_t durationUs);
-    void notifyMorePlayingTimeUs(int64_t timeUs);
-    void notifyMoreRebufferingTimeUs(int64_t timeUs);
-    void notifyRebufferingWhenExit(bool status);
-    void notifySeekComplete();
-    void notifySeekComplete_l();
-    void notifyListener(int msg, int ext1 = 0, int ext2 = 0, const Parcel *in = NULL);
-    void notifyFlagsChanged(uint32_t flags);
+    void notifySetDataSourceCompleted(int64_t srcId, status_t err);
+    void notifyPrepareCompleted(int64_t srcId, status_t err);
+    void notifyResetComplete(int64_t srcId);
+    void notifySetSurfaceComplete(int64_t srcId);
+    void notifyDuration(int64_t srcId, int64_t durationUs);
+    void notifyMorePlayingTimeUs(int64_t srcId, int64_t timeUs);
+    void notifyMoreRebufferingTimeUs(int64_t srcId, int64_t timeUs);
+    void notifyRebufferingWhenExit(int64_t srcId, bool status);
+    void notifySeekComplete(int64_t srcId);
+    void notifySeekComplete_l(int64_t srcId);
+    void notifyListener(int64_t srcId, int msg, int ext1 = 0, int ext2 = 0,
+                        const Parcel *in = NULL);
+    void notifyFlagsChanged(int64_t srcId, uint32_t flags);
 
     // Modular DRM
     virtual status_t prepareDrm(const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId);
@@ -118,6 +119,7 @@
 
     // The following are protected through "mLock"
     // >>>
+    int64_t mSrcId;
     bool mSetSurfaceInProgress;
     int64_t mDurationUs;
     int64_t mPositionUs;
@@ -147,7 +149,8 @@
 
     status_t prepare_l();
     status_t start_l();
-    void notifyListener_l(int msg, int ext1 = 0, int ext2 = 0, const Parcel *in = NULL);
+    void notifyListener_l(int64_t srcId, int msg, int ext1 = 0, int ext2 = 0,
+                          const Parcel *in = NULL);
 
     DISALLOW_EVIL_CONSTRUCTORS(NuPlayer2Driver);
 };
diff --git a/media/libmediaplayerservice/tests/Android.bp b/media/libmediaplayerservice/tests/Android.bp
index d6c1d27..e936bdd 100644
--- a/media/libmediaplayerservice/tests/Android.bp
+++ b/media/libmediaplayerservice/tests/Android.bp
@@ -12,6 +12,7 @@
         "libmediadrm",
         "libutils",
         "android.hardware.drm@1.0",
+        "android.hardware.drm@1.1",
     ],
 
     compile_multilib: "32",
diff --git a/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp b/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
index c5212fc..2c6a41b 100644
--- a/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
+++ b/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
@@ -20,7 +20,7 @@
 
 #include <gtest/gtest.h>
 
-#include <media/Drm.h>
+#include <media/DrmHal.h>
 #include <media/DrmSessionClientInterface.h>
 #include <media/DrmSessionManager.h>
 #include <media/stagefright/foundation/ADebug.h>
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index db07afe..2b33708 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -2955,8 +2955,8 @@
 
         if (mSoftRenderer != NULL) {
             std::list<FrameRenderTracker::Info> doneFrames = mSoftRenderer->render(
-                    buffer->data(), buffer->size(),
-                    mediaTimeUs, renderTimeNs, NULL, buffer->format());
+                    buffer->data(), buffer->size(), mediaTimeUs, renderTimeNs,
+                    mPortBuffers[kPortIndexOutput].size(), buffer->format());
 
             // if we are running, notify rendered frames
             if (!doneFrames.empty() && mState == STARTED && mOnFrameRenderedNotification != NULL) {
diff --git a/media/libstagefright/codecs/on2/dec/SoftVPX.h b/media/libstagefright/codecs/on2/dec/SoftVPX.h
index a01a4f3..9ac2791 100644
--- a/media/libstagefright/codecs/on2/dec/SoftVPX.h
+++ b/media/libstagefright/codecs/on2/dec/SoftVPX.h
@@ -44,7 +44,7 @@
 
 private:
     enum {
-        kNumBuffers = 4
+        kNumBuffers = 16
     };
 
     enum {
diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
index c9ebbdc..838bc5f 100644
--- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp
+++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
@@ -60,7 +60,8 @@
     mConverter = NULL;
 }
 
-void SoftwareRenderer::resetFormatIfChanged(const sp<AMessage> &format) {
+void SoftwareRenderer::resetFormatIfChanged(
+        const sp<AMessage> &format, size_t numOutputBuffers) {
     CHECK(format != NULL);
 
     int32_t colorFormatNew;
@@ -168,7 +169,7 @@
     CHECK_EQ(0,
             native_window_set_usage(
             mNativeWindow.get(),
-            GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_OFTEN
+            GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_RARELY
             | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP));
 
     CHECK_EQ(0,
@@ -184,6 +185,11 @@
     CHECK_EQ(0, native_window_set_buffers_format(
                 mNativeWindow.get(),
                 halFormat));
+    if (OK != native_window_set_buffer_count(
+                mNativeWindow.get(), numOutputBuffers + 4)) {
+        ALOGE("Failed to set native window buffer count to (%zu + 4)",
+                numOutputBuffers);
+    }
 
     // NOTE: native window uses extended right-bottom coordinate
     android_native_rect_t crop;
@@ -219,8 +225,8 @@
 
 std::list<FrameRenderTracker::Info> SoftwareRenderer::render(
         const void *data, size_t , int64_t mediaTimeUs, nsecs_t renderTimeNs,
-        void* /*platformPrivate*/, const sp<AMessage>& format) {
-    resetFormatIfChanged(format);
+        size_t numOutputBuffers, const sp<AMessage>& format) {
+    resetFormatIfChanged(format, numOutputBuffers);
     FrameRenderTracker::Info *info = NULL;
 
     ANativeWindowBuffer *buf;
@@ -243,8 +249,9 @@
     Rect bounds(mCropWidth, mCropHeight);
 
     void *dst;
-    CHECK_EQ(0, mapper.lock(
-                buf->handle, GRALLOC_USAGE_SW_WRITE_OFTEN, bounds, &dst));
+    CHECK_EQ(0, mapper.lock(buf->handle,
+            GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_RARELY,
+            bounds, &dst));
 
     // TODO move the other conversions also into ColorConverter, and
     // fix cropping issues (when mCropLeft/Top != 0 or mWidth != mCropWidth)
diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
index bc3e57c..8f349fc 100644
--- a/media/libstagefright/httplive/M3UParser.cpp
+++ b/media/libstagefright/httplive/M3UParser.cpp
@@ -659,10 +659,13 @@
         }
 
         if (!line.startsWith("#")) {
+            if (itemMeta == NULL) {
+                ALOGV("itemMeta == NULL");
+                return ERROR_MALFORMED;
+            }
             if (!mIsVariantPlaylist) {
                 int64_t durationUs;
-                if (itemMeta == NULL
-                        || !itemMeta->findInt64("durationUs", &durationUs)) {
+                if (!itemMeta->findInt64("durationUs", &durationUs)) {
                     return ERROR_MALFORMED;
                 }
                 itemMeta->setInt32("discontinuity-sequence",
diff --git a/media/libstagefright/include/SoftwareRenderer.h b/media/libstagefright/include/SoftwareRenderer.h
index e04b59f..c286516 100644
--- a/media/libstagefright/include/SoftwareRenderer.h
+++ b/media/libstagefright/include/SoftwareRenderer.h
@@ -39,7 +39,7 @@
 
     std::list<FrameRenderTracker::Info> render(
             const void *data, size_t size, int64_t mediaTimeUs, nsecs_t renderTimeNs,
-            void *platformPrivate, const sp<AMessage> &format);
+            size_t numOutputBuffers, const sp<AMessage> &format);
     void clearTracker();
 
 private:
@@ -59,10 +59,11 @@
     HDRStaticInfo mHDRStaticInfo;
     FrameRenderTracker mRenderTracker;
 
+    void resetFormatIfChanged(
+            const sp<AMessage> &format, size_t numOutputBuffers);
+
     SoftwareRenderer(const SoftwareRenderer &);
     SoftwareRenderer &operator=(const SoftwareRenderer &);
-
-    void resetFormatIfChanged(const sp<AMessage> &format);
 };
 
 }  // namespace android
diff --git a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
index 1ba5852..d650224 100644
--- a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
+++ b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
@@ -41,7 +41,7 @@
     mLooper->start(
             false, // runOnCallingThread
             false, // canCallJava
-            ANDROID_PRIORITY_FOREGROUND);
+            ANDROID_PRIORITY_AUDIO);
 }
 
 void SimpleSoftOMXComponent::prepareForDestruction() {
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index eecc858..fe08ab9 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -240,7 +240,7 @@
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
     Vector<uint8_t> session;
-    status_t status = mObj->mDrm->openSession(session);
+    status_t status = mObj->mDrm->openSession(DrmPlugin::kSecurityLevelMax, session);
     if (status == OK) {
         mObj->mIds.push_front(session);
         List<idvec_t>::iterator iter = mObj->mIds.begin();
diff --git a/packages/MediaComponents/res/drawable/ic_arrow_back.xml b/packages/MediaComponents/res/drawable/ic_arrow_back.xml
index 5aba8c6..2b5f71e 100644
--- a/packages/MediaComponents/res/drawable/ic_arrow_back.xml
+++ b/packages/MediaComponents/res/drawable/ic_arrow_back.xml
@@ -1,6 +1,6 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="40dp"
-        android:height="40dp"
+        android:width="24dp"
+        android:height="24dp"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
diff --git a/packages/MediaComponents/res/drawable/ic_launch.xml b/packages/MediaComponents/res/drawable/ic_launch.xml
new file mode 100644
index 0000000..f7af6aa
--- /dev/null
+++ b/packages/MediaComponents/res/drawable/ic_launch.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M19,19H5V5h7V3H5c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2v-7h-2v7zM14,3v2h3.59l-9.83,9.83 1.41,1.41L19,6.41V10h2V3h-7z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/MediaComponents/res/layout/media_controller.xml b/packages/MediaComponents/res/layout/media_controller.xml
index dd56e7c..f9ebd44 100644
--- a/packages/MediaComponents/res/layout/media_controller.xml
+++ b/packages/MediaComponents/res/layout/media_controller.xml
@@ -24,35 +24,88 @@
     <RelativeLayout
         android:id="@+id/title_bar"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content">
+        android:layout_height="wrap_content"
+        style="@style/TitleBar">
 
-        <RadioButton
-            android:id="@+id/back"
+        <LinearLayout
+            android:id="@+id/title_bar_left"
+            android:gravity="center"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_alignParentStart="true"
+            android:layout_alignParentLeft="true"
             android:layout_centerVertical="true"
-            android:checked="true"
-            android:visibility="gone"/>
+            android:orientation="horizontal">
 
-        <TextView
-            android:id="@+id/title_text"
+            <ImageButton
+                android:id="@+id/back"
+                android:clickable="true"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignParentStart="true"
+                android:layout_centerVertical="true"
+                android:paddingLeft="5dip"
+                android:visibility="visible"
+                style="@style/TitleBarButton.Back"/>
+
+            <TextView
+                android:id="@+id/title_text"
+                android:ellipsize="end"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_toRightOf="@id/back"
+                android:layout_centerVertical="true"
+                android:maxLines="1"
+                android:paddingLeft="5dip"
+                android:paddingRight="5dip"
+                android:textSize="15sp"
+                android:textColor="#FFFFFFFF"/>
+        </LinearLayout>
+
+        <LinearLayout
+            android:id="@+id/title_bar_right"
+            android:gravity="center"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_toRightOf="@id/back"
+            android:layout_alignParentRight="true"
             android:layout_centerVertical="true"
-            android:layout_marginLeft="15dp"
-            android:paddingTop="4dp"
-            android:paddingStart="4dp"
-            android:paddingEnd="4dp"
-            android:textSize="20sp"
-            android:textColor="#FFFFFFFF" />
+            android:orientation="horizontal">
 
-        <view class="com.android.support.mediarouter.app.MediaRouteButton" android:id="@+id/cast"
-            android:layout_alignParentEnd="true"
-            android:layout_centerVertical="true"
-            android:visibility="gone"
-            style="@style/TitleBarButton" />
+            <LinearLayout
+                android:id="@+id/ad"
+                android:clickable="true"
+                android:gravity="center"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignParentRight="true"
+                android:layout_centerVertical="true"
+                android:paddingLeft="5dip"
+                android:paddingRight="10dip"
+                android:orientation="horizontal">
+
+                <TextView
+                    android:id="@+id/ad_text"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_centerVertical="true"
+                    android:paddingRight="5dip"
+                    android:text="Visit Advertiser"
+                    android:textSize="10sp"
+                    android:textColor="#FFFFFFFF" />
+
+                <ImageButton
+                    android:id="@+id/ad_launch"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_centerVertical="true"
+                    style="@style/TitleBarButton.Launch" />
+            </LinearLayout>
+
+            <view class="com.android.support.mediarouter.app.MediaRouteButton"
+                android:id="@+id/cast"
+                android:layout_centerVertical="true"
+                android:visibility="visible"
+                style="@style/TitleBarButton" />
+        </LinearLayout>
 
     </RelativeLayout>
 
diff --git a/packages/MediaComponents/res/values/style.xml b/packages/MediaComponents/res/values/style.xml
index c59380c..db5e8f3 100644
--- a/packages/MediaComponents/res/values/style.xml
+++ b/packages/MediaComponents/res/values/style.xml
@@ -26,12 +26,22 @@
         <item name="android:src">@drawable/ic_rewind_10</item>
     </style>
 
+    <style name="TitleBar">
+        <item name="android:layout_height">46dp</item>
+    </style>
 
     <style name="TitleBarButton">
         <item name="android:background">@null</item>
         <item name="android:layout_width">36dp</item>
         <item name="android:layout_height">36dp</item>
-        <item name="android:layout_margin">10dp</item>
+    </style>
+
+    <style name="TitleBarButton.Back">
+        <item name="android:src">@drawable/ic_arrow_back</item>
+    </style>
+
+    <style name="TitleBarButton.Launch">
+        <item name="android:src">@drawable/ic_launch</item>
     </style>
 
     <style name="BottomBarButton">
diff --git a/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java b/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java
index 3e6d98f..7e928d7 100644
--- a/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java
@@ -91,10 +91,4 @@
             mCallback.onGetRootResult(rootHints, rootMediaId, rootExtra);
         });
     }
-
-    public void onCustomLayoutChanged(final List<CommandButton> layout) {
-        getCallbackExecutor().execute(() -> {
-            mCallback.onCustomLayoutChanged(layout);
-        });
-    }
 }
diff --git a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java b/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
index 1401ab8..5ae37ee 100644
--- a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
@@ -44,9 +44,6 @@
 import android.support.annotation.GuardedBy;
 import android.util.Log;
 
-import com.android.media.MediaSession2Impl.CommandButtonImpl;
-
-import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.Executor;
@@ -220,7 +217,11 @@
     }
 
     Context getContext() {
-      return mContext;
+        return mContext;
+    }
+
+    MediaController2 getInstance() {
+        return mInstance;
     }
 
     @Override
@@ -503,10 +504,7 @@
         sendTransportControlCommand(MediaSession2.COMMAND_CODE_PLAYBACK_SET_PLAYLIST_PARAMS, args);
     }
 
-    ///////////////////////////////////////////////////
-    // Protected or private methods
-    ///////////////////////////////////////////////////
-    private void pushPlaybackStateChanges(final PlaybackState2 state) {
+    void pushPlaybackStateChanges(final PlaybackState2 state) {
         synchronized (mLock) {
             mPlaybackState = state;
         }
@@ -518,7 +516,7 @@
         });
     }
 
-    private void pushPlaylistParamsChanges(final PlaylistParams params) {
+    void pushPlaylistParamsChanges(final PlaylistParams params) {
         synchronized (mLock) {
             mPlaylistParams = params;
         }
@@ -530,7 +528,7 @@
         });
     }
 
-    private void pushPlaybackInfoChanges(final PlaybackInfo info) {
+    void pushPlaybackInfoChanges(final PlaybackInfo info) {
         synchronized (mLock) {
             mPlaybackInfo = info;
         }
@@ -542,7 +540,7 @@
         });
     }
 
-    private void pushPlaylistChanges(final List<Bundle> list) {
+    void pushPlaylistChanges(final List<Bundle> list) {
         final List<MediaItem2> playlist = new ArrayList<>();
         for (int i = 0; i < list.size(); i++) {
             MediaItem2 item = MediaItem2.fromBundle(mContext, list.get(i));
@@ -563,7 +561,7 @@
     }
 
     // Should be used without a lock to prevent potential deadlock.
-    private void onConnectedNotLocked(IMediaSession2 sessionBinder,
+    void onConnectedNotLocked(IMediaSession2 sessionBinder,
             final CommandGroup commandGroup, final PlaybackState2 state, final PlaybackInfo info,
             final PlaylistParams params, final List<MediaItem2> playlist, final int ratingType,
             final PendingIntent sessionActivity) {
@@ -624,7 +622,7 @@
         }
     }
 
-    private void onCustomCommand(final Command command, final Bundle args,
+    void onCustomCommand(final Command command, final Bundle args,
             final ResultReceiver receiver) {
         if (DEBUG) {
             Log.d(TAG, "onCustomCommand cmd=" + command);
@@ -635,193 +633,10 @@
         });
     }
 
-    // TODO(jaewan): Pull out this from the controller2, and rename it to the MediaController2Stub
-    //               or MediaBrowser2Stub.
-    static class MediaSession2CallbackStub extends IMediaSession2Callback.Stub {
-        private final WeakReference<MediaController2Impl> mController;
-
-        private MediaSession2CallbackStub(MediaController2Impl controller) {
-            mController = new WeakReference<>(controller);
-        }
-
-        private MediaController2Impl getController() throws IllegalStateException {
-            final MediaController2Impl controller = mController.get();
-            if (controller == null) {
-                throw new IllegalStateException("Controller is released");
-            }
-            return controller;
-        }
-
-        // TODO(jaewan): Refactor code to get rid of these pattern.
-        private MediaBrowser2Impl getBrowser() throws IllegalStateException {
-            final MediaController2Impl controller = getController();
-            if (controller instanceof MediaBrowser2Impl) {
-                return (MediaBrowser2Impl) controller;
-            }
-            return null;
-        }
-
-        public void destroy() {
-            mController.clear();
-        }
-
-        @Override
-        public void onPlaybackStateChanged(Bundle state) throws RuntimeException {
-            final MediaController2Impl controller;
-            try {
-                controller = getController();
-            } catch (IllegalStateException e) {
-                Log.w(TAG, "Don't fail silently here. Highly likely a bug");
-                return;
-            }
-            controller.pushPlaybackStateChanges(
-                    PlaybackState2.fromBundle(controller.getContext(), state));
-        }
-
-        @Override
-        public void onPlaylistChanged(List<Bundle> playlist) throws RuntimeException {
-            final MediaController2Impl controller;
-            try {
-                controller = getController();
-            } catch (IllegalStateException e) {
-                Log.w(TAG, "Don't fail silently here. Highly likely a bug");
-                return;
-            }
-            if (playlist == null) {
-                return;
-            }
-            controller.pushPlaylistChanges(playlist);
-        }
-
-        @Override
-        public void onPlaylistParamsChanged(Bundle params) throws RuntimeException {
-            final MediaController2Impl controller;
-            try {
-                controller = getController();
-            } catch (IllegalStateException e) {
-                Log.w(TAG, "Don't fail silently here. Highly likely a bug");
-                return;
-            }
-            controller.pushPlaylistParamsChanges(
-                    PlaylistParams.fromBundle(controller.getContext(), params));
-        }
-
-        @Override
-        public void onPlaybackInfoChanged(Bundle playbackInfo) throws RuntimeException {
-            if (DEBUG) {
-                Log.d(TAG, "onPlaybackInfoChanged");
-            }
-            final MediaController2Impl controller;
-            try {
-                controller = getController();
-            } catch (IllegalStateException e) {
-                Log.w(TAG, "Don't fail silently here. Highly likely a bug");
-                return;
-            }
-            controller.pushPlaybackInfoChanges(
-                    PlaybackInfoImpl.fromBundle(controller.getContext(), playbackInfo));
-        }
-
-        @Override
-        public void onConnected(IMediaSession2 sessionBinder, Bundle commandGroup,
-                Bundle playbackState, Bundle playbackInfo, Bundle playlistParams, List<Bundle>
-                playlist, int ratingType, PendingIntent sessionActivity) {
-            final MediaController2Impl controller = mController.get();
-            if (controller == null) {
-                if (DEBUG) {
-                    Log.d(TAG, "onConnected after MediaController2.close()");
-                }
-                return;
-            }
-            final Context context = controller.getContext();
-            List<MediaItem2> list = new ArrayList<>();
-            for (int i = 0; i < playlist.size(); i++) {
-                MediaItem2 item = MediaItem2.fromBundle(context, playlist.get(i));
-                if (item != null) {
-                    list.add(item);
-                }
-            }
-            controller.onConnectedNotLocked(sessionBinder,
-                    CommandGroup.fromBundle(context, commandGroup),
-                    PlaybackState2.fromBundle(context, playbackState),
-                    PlaybackInfoImpl.fromBundle(context, playbackInfo),
-                    PlaylistParams.fromBundle(context, playlistParams),
-                    list, ratingType, sessionActivity);
-        }
-
-        @Override
-        public void onDisconnected() {
-            final MediaController2Impl controller = mController.get();
-            if (controller == null) {
-                if (DEBUG) {
-                    Log.d(TAG, "onDisconnected after MediaController2.close()");
-                }
-                return;
-            }
-            controller.mInstance.close();
-        }
-
-        @Override
-        public void onGetRootResult(Bundle rootHints, String rootMediaId, Bundle rootExtra)
-                throws RuntimeException {
-            final MediaBrowser2Impl browser;
-            try {
-                browser = getBrowser();
-            } catch (IllegalStateException e) {
-                Log.w(TAG, "Don't fail silently here. Highly likely a bug");
-                return;
-            }
-            if (browser == null) {
-                // TODO(jaewan): Revisit here. Could be a bug
-                return;
-            }
-            browser.onGetRootResult(rootHints, rootMediaId, rootExtra);
-        }
-
-        @Override
-        public void onCustomLayoutChanged(List<Bundle> commandButtonlist) {
-            if (commandButtonlist == null) {
-                // Illegal call. Ignore
-                return;
-            }
-            // TODO(jaewan): Fix here. It's controller feature so shouldn't use browser
-            final MediaBrowser2Impl browser;
-            try {
-                browser = getBrowser();
-            } catch (IllegalStateException e) {
-                Log.w(TAG, "Don't fail silently here. Highly likely a bug");
-                return;
-            }
-            if (browser == null) {
-                // TODO(jaewan): Revisit here. Could be a bug
-                return;
-            }
-            List<CommandButton> layout = new ArrayList<>();
-            for (int i = 0; i < commandButtonlist.size(); i++) {
-                CommandButton button = CommandButtonImpl.fromBundle(
-                        browser.getContext(), commandButtonlist.get(i));
-                if (button != null) {
-                    layout.add(button);
-                }
-            }
-            browser.onCustomLayoutChanged(layout);
-        }
-
-        @Override
-        public void sendCustomCommand(Bundle commandBundle, Bundle args, ResultReceiver receiver) {
-            final MediaController2Impl controller;
-            try {
-                controller = getController();
-            } catch (IllegalStateException e) {
-                Log.w(TAG, "Don't fail silently here. Highly likely a bug");
-                return;
-            }
-            Command command = Command.fromBundle(controller.getContext(), commandBundle);
-            if (command == null) {
-                return;
-            }
-            controller.onCustomCommand(command, args, receiver);
-        }
+    void onCustomLayoutChanged(final List<CommandButton> layout) {
+        mCallbackExecutor.execute(() -> {
+            mCallback.onCustomLayoutChanged(layout);
+        });
     }
 
     // This will be called on the main thread.
diff --git a/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java b/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
index 77bd334..b9dffcf 100644
--- a/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
@@ -26,6 +26,7 @@
 import android.media.MediaPlayerInterface;
 import android.media.MediaSession2;
 import android.media.MediaSession2.ControllerInfo;
+import android.media.MediaSession2.SessionCallback;
 import android.media.MediaSessionService2;
 import android.media.SessionToken2;
 import android.media.VolumeProvider2;
@@ -87,6 +88,12 @@
         }
 
         @Override
+        MediaLibrarySessionCallback getCallback() {
+            // Equivalent to the (MediaLibrarySessionCallback) super.getCallback().
+            return mCallback;
+        }
+
+        @Override
         public void notifyChildrenChanged_impl(ControllerInfo controller, String parentId,
                 Bundle options) {
             // TODO(jaewan): Implements
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2CallbackStub.java b/packages/MediaComponents/src/com/android/media/MediaSession2CallbackStub.java
new file mode 100644
index 0000000..07edf7e
--- /dev/null
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2CallbackStub.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.media;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.media.MediaItem2;
+import android.media.MediaSession2.Command;
+import android.media.MediaSession2.CommandButton;
+import android.media.MediaSession2.CommandGroup;
+import android.media.MediaSession2.PlaylistParams;
+import android.media.PlaybackState2;
+import android.os.Bundle;
+import android.os.ResultReceiver;
+import android.util.Log;
+
+import com.android.media.MediaController2Impl.PlaybackInfoImpl;
+import com.android.media.MediaSession2Impl.CommandButtonImpl;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+
+public class MediaSession2CallbackStub extends IMediaSession2Callback.Stub {
+    private static final String TAG = "MS2CallbackStub";
+    private static final boolean DEBUG = true; // TODO(jaewan): Change
+
+    private final WeakReference<MediaController2Impl> mController;
+
+    MediaSession2CallbackStub(MediaController2Impl controller) {
+        mController = new WeakReference<>(controller);
+    }
+
+    private MediaController2Impl getController() throws IllegalStateException {
+        final MediaController2Impl controller = mController.get();
+        if (controller == null) {
+            throw new IllegalStateException("Controller is released");
+        }
+        return controller;
+    }
+
+    private MediaBrowser2Impl getBrowser() throws IllegalStateException {
+        final MediaController2Impl controller = getController();
+        if (controller instanceof MediaBrowser2Impl) {
+            return (MediaBrowser2Impl) controller;
+        }
+        return null;
+    }
+
+    public void destroy() {
+        mController.clear();
+    }
+
+    @Override
+    public void onPlaybackStateChanged(Bundle state) throws RuntimeException {
+        final MediaController2Impl controller;
+        try {
+            controller = getController();
+        } catch (IllegalStateException e) {
+            Log.w(TAG, "Don't fail silently here. Highly likely a bug");
+            return;
+        }
+        controller.pushPlaybackStateChanges(
+                PlaybackState2.fromBundle(controller.getContext(), state));
+    }
+
+    @Override
+    public void onPlaylistChanged(List<Bundle> playlist) throws RuntimeException {
+        final MediaController2Impl controller;
+        try {
+            controller = getController();
+        } catch (IllegalStateException e) {
+            Log.w(TAG, "Don't fail silently here. Highly likely a bug");
+            return;
+        }
+        if (playlist == null) {
+            return;
+        }
+        controller.pushPlaylistChanges(playlist);
+    }
+
+    @Override
+    public void onPlaylistParamsChanged(Bundle params) throws RuntimeException {
+        final MediaController2Impl controller;
+        try {
+            controller = getController();
+        } catch (IllegalStateException e) {
+            Log.w(TAG, "Don't fail silently here. Highly likely a bug");
+            return;
+        }
+        controller.pushPlaylistParamsChanges(
+                PlaylistParams.fromBundle(controller.getContext(), params));
+    }
+
+    @Override
+    public void onPlaybackInfoChanged(Bundle playbackInfo) throws RuntimeException {
+        if (DEBUG) {
+            Log.d(TAG, "onPlaybackInfoChanged");
+        }
+        final MediaController2Impl controller;
+        try {
+            controller = getController();
+        } catch (IllegalStateException e) {
+            Log.w(TAG, "Don't fail silently here. Highly likely a bug");
+            return;
+        }
+        controller.pushPlaybackInfoChanges(
+                PlaybackInfoImpl.fromBundle(controller.getContext(), playbackInfo));
+    }
+
+    @Override
+    public void onConnected(IMediaSession2 sessionBinder, Bundle commandGroup,
+            Bundle playbackState, Bundle playbackInfo, Bundle playlistParams, List<Bundle>
+            playlist, int ratingType, PendingIntent sessionActivity) {
+        final MediaController2Impl controller = mController.get();
+        if (controller == null) {
+            if (DEBUG) {
+                Log.d(TAG, "onConnected after MediaController2.close()");
+            }
+            return;
+        }
+        final Context context = controller.getContext();
+        List<MediaItem2> list = new ArrayList<>();
+        for (int i = 0; i < playlist.size(); i++) {
+            MediaItem2 item = MediaItem2.fromBundle(context, playlist.get(i));
+            if (item != null) {
+                list.add(item);
+            }
+        }
+        controller.onConnectedNotLocked(sessionBinder,
+                CommandGroup.fromBundle(context, commandGroup),
+                PlaybackState2.fromBundle(context, playbackState),
+                PlaybackInfoImpl.fromBundle(context, playbackInfo),
+                PlaylistParams.fromBundle(context, playlistParams),
+                list, ratingType, sessionActivity);
+    }
+
+    @Override
+    public void onDisconnected() {
+        final MediaController2Impl controller = mController.get();
+        if (controller == null) {
+            if (DEBUG) {
+                Log.d(TAG, "onDisconnected after MediaController2.close()");
+            }
+            return;
+        }
+        controller.getInstance().close();
+    }
+
+    @Override
+    public void onCustomLayoutChanged(List<Bundle> commandButtonlist) {
+        if (commandButtonlist == null) {
+            // Illegal call. Ignore
+            return;
+        }
+        final MediaController2Impl controller;
+        try {
+            controller = getController();
+        } catch (IllegalStateException e) {
+            Log.w(TAG, "Don't fail silently here. Highly likely a bug");
+            return;
+        }
+        if (controller == null) {
+            // TODO(jaewan): Revisit here. Could be a bug
+            return;
+        }
+        List<CommandButton> layout = new ArrayList<>();
+        for (int i = 0; i < commandButtonlist.size(); i++) {
+            CommandButton button = CommandButtonImpl.fromBundle(
+                    controller.getContext(), commandButtonlist.get(i));
+            if (button != null) {
+                layout.add(button);
+            }
+        }
+        controller.onCustomLayoutChanged(layout);
+    }
+
+    @Override
+    public void sendCustomCommand(Bundle commandBundle, Bundle args, ResultReceiver receiver) {
+        final MediaController2Impl controller;
+        try {
+            controller = getController();
+        } catch (IllegalStateException e) {
+            Log.w(TAG, "Don't fail silently here. Highly likely a bug");
+            return;
+        }
+        Command command = Command.fromBundle(controller.getContext(), commandBundle);
+        if (command == null) {
+            return;
+        }
+        controller.onCustomCommand(command, args, receiver);
+    }
+
+    ////////////////////////////////////////////////////////////////////////////////////////////
+    // MediaBrowser specific
+    ////////////////////////////////////////////////////////////////////////////////////////////
+    @Override
+    public void onGetRootResult(Bundle rootHints, String rootMediaId, Bundle rootExtra)
+            throws RuntimeException {
+        final MediaBrowser2Impl browser;
+        try {
+            browser = getBrowser();
+        } catch (IllegalStateException e) {
+            Log.w(TAG, "Don't fail silently here. Highly likely a bug");
+            return;
+        }
+        if (browser == null) {
+            // TODO(jaewan): Revisit here. Could be a bug
+            return;
+        }
+        browser.onGetRootResult(rootHints, rootMediaId, rootExtra);
+    }
+}
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java b/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
index d396d73..43ad49d 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
@@ -21,7 +21,6 @@
 import android.media.MediaController2;
 import android.media.MediaItem2;
 import android.media.MediaLibraryService2.LibraryRoot;
-import android.media.MediaLibraryService2.MediaLibrarySessionCallback;
 import android.media.MediaSession2;
 import android.media.MediaSession2.Command;
 import android.media.MediaSession2.CommandButton;
@@ -40,6 +39,7 @@
 import android.util.ArrayMap;
 import android.util.Log;
 
+import com.android.media.MediaLibraryService2Impl.MediaLibrarySessionImpl;
 import com.android.media.MediaSession2Impl.CommandButtonImpl;
 import com.android.media.MediaSession2Impl.ControllerInfoImpl;
 
@@ -94,6 +94,27 @@
         return session;
     }
 
+    private MediaLibrarySessionImpl getLibrarySession() throws IllegalStateException {
+        final MediaSession2Impl session = getSession();
+        if (!(session instanceof MediaLibrarySessionImpl)) {
+            throw new RuntimeException("Session isn't a library session");
+        }
+        return (MediaLibrarySessionImpl) session;
+    }
+
+    private ControllerInfo getController(IMediaSession2Callback caller) {
+        // TODO(jaewan): Find a way to return connection-in-progress-controller
+        //               to be included here, because session owner may want to send some datas
+        //               while onConnected() hasn't returned.
+        synchronized (mLock) {
+            return mControllers.get(caller.asBinder());
+        }
+    }
+
+    //////////////////////////////////////////////////////////////////////////////////////////////
+    // AIDL methods for session overrides
+    //////////////////////////////////////////////////////////////////////////////////////////////
+
     @Override
     public void connect(String callingPackage, final IMediaSession2Callback callback)
             throws RuntimeException {
@@ -485,32 +506,28 @@
         });
     }
 
+    //////////////////////////////////////////////////////////////////////////////////////////////
+    // AIDL methods for LibrarySession overrides
+    //////////////////////////////////////////////////////////////////////////////////////////////
+
     @Override
     public void getBrowserRoot(IMediaSession2Callback caller, Bundle rootHints)
             throws RuntimeException {
-        final MediaSession2Impl sessionImpl = getSession();
-        if (!(sessionImpl.getCallback() instanceof MediaLibrarySessionCallback)) {
-            if (DEBUG) {
-                Log.d(TAG, "Session cannot hand getLibraryRoot()");
-            }
-            return;
-        }
+        final MediaLibrarySessionImpl sessionImpl = getLibrarySession();
         final ControllerInfo controller = getController(caller);
         if (controller == null) {
             if (DEBUG) {
-                Log.d(TAG, "getBrowerRoot from a controller that hasn't connected. Ignore");
+                Log.d(TAG, "getBrowerRoot() from a controller that hasn't connected. Ignore");
             }
             return;
         }
         sessionImpl.getCallbackExecutor().execute(() -> {
-            final MediaSession2Impl session = mSession.get();
+            final MediaLibrarySessionImpl session = getLibrarySession();
             if (session == null) {
                 return;
             }
-            final MediaLibrarySessionCallback libraryCallback =
-                    (MediaLibrarySessionCallback) session.getCallback();
             final ControllerInfoImpl controllerImpl = ControllerInfoImpl.from(controller);
-            LibraryRoot root = libraryCallback.onGetRoot(controller, rootHints);
+            LibraryRoot root = session.getCallback().onGetRoot(controller, rootHints);
             try {
                 controllerImpl.getControllerBinder().onGetRootResult(rootHints,
                         root == null ? null : root.getRootId(),
@@ -522,15 +539,9 @@
         });
     }
 
-    private ControllerInfo getController(IMediaSession2Callback caller) {
-        // TODO(jaewan): Device a way to return connection-in-progress-controller
-        //               to be included here, because session owner may want to send some datas
-        //               while onConnected() hasn't returned.
-        synchronized (mLock) {
-            return mControllers.get(caller.asBinder());
-        }
-    }
-
+    //////////////////////////////////////////////////////////////////////////////////////////////
+    // APIs for MediaSession2Impl
+    //////////////////////////////////////////////////////////////////////////////////////////////
     // TODO(jaewan): Need a way to get controller with permissions
     public List<ControllerInfo> getControllers() {
         ArrayList<ControllerInfo> controllers = new ArrayList<>();
diff --git a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
index dfc0792..318cbf9 100644
--- a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
@@ -54,6 +54,7 @@
 
     static final String ARGUMENT_KEY_FULLSCREEN = "fullScreen";
 
+    // TODO: Move these constants to public api to support custom video view.
     static final String KEY_STATE_CONTAINS_SUBTITLE = "StateContainsSubtitle";
     static final String EVENT_UPDATE_SUBTITLE_STATUS = "UpdateSubtitleStatus";
 
@@ -72,9 +73,7 @@
     private TextView mTitleView;
     private int mDuration;
     private int mPrevState;
-    private int mCurrentVisibility;
     private long mPlaybackActions;
-    private boolean mShowing;
     private boolean mDragging;
     private boolean mIsFullScreen;
     private boolean mOverflowExpanded;
@@ -233,6 +232,7 @@
     public void setEnabled_impl(boolean enabled) {
         super.setEnabled_impl(enabled);
 
+        // TODO: Merge the below code with disableUnsupportedButtons().
         if (mPlayPauseButton != null) {
             mPlayPauseButton.setEnabled(enabled);
         }
@@ -255,24 +255,15 @@
     }
 
     @Override
-    public void onVisibilityAggregated_impl(boolean invisible) {
-        super.onVisibilityAggregated_impl(invisible);
+    public void onVisibilityAggregated_impl(boolean isVisible) {
+        super.onVisibilityAggregated_impl(isVisible);
 
-        int visibility = mInstance.getVisibility();
-        if (mCurrentVisibility != visibility) {
-            mInstance.setVisibility(visibility);
-            mCurrentVisibility = visibility;
-
-            if (visibility == View.VISIBLE) {
-                setProgress();
-                disableUnsupportedButtons();
-                // cause the progress bar to be updated even if mShowing
-                // was already true.  This happens, for example, if we're
-                // paused with the progress bar showing the user hits play.
-                mInstance.post(mShowProgress);
-            } else if (visibility == View.GONE) {
-                mInstance.removeCallbacks(mShowProgress);
-            }
+        if (isVisible) {
+            disableUnsupportedButtons();
+            mInstance.removeCallbacks(mUpdateProgress);
+            mInstance.post(mUpdateProgress);
+        } else {
+            mInstance.removeCallbacks(mUpdateProgress);
         }
     }
 
@@ -465,12 +456,13 @@
         }
     }
 
-    private final Runnable mShowProgress = new Runnable() {
+    private final Runnable mUpdateProgress = new Runnable() {
         @Override
         public void run() {
             int pos = setProgress();
-            if (!mDragging && mShowing && isPlaying()) {
-                mInstance.postDelayed(mShowProgress,
+            boolean isShowing = mInstance.getVisibility() == View.VISIBLE;
+            if (!mDragging && isShowing && isPlaying()) {
+                mInstance.postDelayed(mUpdateProgress,
                         DEFAULT_PROGRESS_UPDATE_TIME_MS - (pos % DEFAULT_PROGRESS_UPDATE_TIME_MS));
             }
         }
@@ -557,7 +549,7 @@
             // the seekbar and b) once the user is done dragging the thumb
             // we will post one of these messages to the queue again and
             // this ensures that there will be exactly one message queued up.
-            mInstance.removeCallbacks(mShowProgress);
+            mInstance.removeCallbacks(mUpdateProgress);
 
             // Check if playback is currently stopped. In this case, update the pause button to
             // show the play image instead of the replay image.
@@ -602,7 +594,7 @@
             // Ensure that progress is properly updated in the future,
             // the call to show() does not guarantee this because it is a
             // no-op if we are already showing.
-            mInstance.post(mShowProgress);
+            mInstance.post(mUpdateProgress);
         }
     };
 
@@ -735,6 +727,8 @@
                                 ApiHelper.getLibResources().getDrawable(
                                         R.drawable.ic_pause_circle_filled, null));
                         mPlayPauseButton.setContentDescription(mPauseDescription);
+                        mInstance.removeCallbacks(mUpdateProgress);
+                        mInstance.post(mUpdateProgress);
                         break;
                     case PlaybackState.STATE_PAUSED:
                         mPlayPauseButton.setImageDrawable(
diff --git a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
index 256003f..ea7e714 100644
--- a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
@@ -31,7 +31,9 @@
 import android.media.ClosedCaptionRenderer;
 import android.media.Metadata;
 import android.media.PlaybackParams;
+import android.media.SRTRenderer;
 import android.media.SubtitleController;
+import android.media.TimedText;
 import android.media.TtmlRenderer;
 import android.media.WebVttRenderer;
 import android.media.session.MediaController;
@@ -122,6 +124,7 @@
     private int mVideoWidth;
     private int mVideoHeight;
 
+    private ArrayList<Integer> mSubtitleTrackIndices;
     private SubtitleView mSubtitleView;
     private boolean mSubtitleEnabled;
     private int mSelectedTrackIndex;  // selected subtitle track index as MediaPlayer2 returns
@@ -191,13 +194,11 @@
         if (enableControlView) {
             mMediaControlView = new MediaControlView2(mInstance.getContext());
         }
-        boolean enableSubtitle = (attrs == null) || attrs.getAttributeBooleanValue(
+
+        mSubtitleEnabled = (attrs == null) || attrs.getAttributeBooleanValue(
                 "http://schemas.android.com/apk/res/android",
-                "enableSubtitle", true);
-        if (enableSubtitle) {
-            Log.d(TAG, "enableSubtitle attribute is true.");
-            // TODO: implement
-        }
+                "enableSubtitle", false);
+
         int viewType = (attrs == null) ? VideoView2.VIEW_TYPE_SURFACEVIEW
                 : attrs.getAttributeIntValue(
                 "http://schemas.android.com/apk/res/android",
@@ -240,27 +241,8 @@
 
     @Override
     public void setSubtitleEnabled_impl(boolean enable) {
-        if (enable) {
-            // Retrieve all tracks that belong to the current video.
-            MediaPlayer.TrackInfo[] trackInfos = mMediaPlayer.getTrackInfo();
-
-            List<Integer> subtitleTrackIndices = new ArrayList<>();
-            for (int i = 0; i < trackInfos.length; ++i) {
-                int trackType = trackInfos[i].getTrackType();
-                if (trackType == MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
-                    subtitleTrackIndices.add(i);
-                }
-            }
-            if (subtitleTrackIndices.size() > 0) {
-                // Select first subtitle track
-                mSelectedTrackIndex = subtitleTrackIndices.get(0);
-                mMediaPlayer.selectTrack(mSelectedTrackIndex);
-            }
-        } else {
-            if (mSelectedTrackIndex != INVALID_TRACK_INDEX) {
-                mMediaPlayer.deselectTrack(mSelectedTrackIndex);
-                mSelectedTrackIndex = INVALID_TRACK_INDEX;
-            }
+        if (enable != mSubtitleEnabled) {
+            selectOrDeselectSubtitle(enable);
         }
         mSubtitleEnabled = enable;
     }
@@ -572,7 +554,13 @@
             controller.registerRenderer(new TtmlRenderer(context));
             controller.registerRenderer(new Cea708CaptionRenderer(context));
             controller.registerRenderer(new ClosedCaptionRenderer(context));
-            mMediaPlayer.setSubtitleAnchor(controller, (SubtitleController.Anchor) mSubtitleView);
+            controller.registerRenderer(new SRTRenderer(context));
+            mMediaPlayer.setSubtitleAnchor(
+                    controller, (SubtitleController.Anchor) mSubtitleView);
+            // TODO: Remove timed text related code later once relevant Renderer is defined.
+            // This is just for debugging purpose.
+            mMediaPlayer.setOnTimedTextListener(mTimedTextListener);
+
             mMediaPlayer.setOnPreparedListener(mPreparedListener);
             mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
             mMediaPlayer.setOnCompletionListener(mCompletionListener);
@@ -622,7 +610,6 @@
     /*
      * Reset the media player in any state
      */
-    // TODO: Figure out if the legacy code's boolean parameter: cleartargetstate is necessary.
     private void resetPlayer() {
         if (mMediaPlayer != null) {
             mMediaPlayer.reset();
@@ -774,7 +761,58 @@
             return false;
         }
         PlaybackInfo playbackInfo = mMediaController.getPlaybackInfo();
-        return (playbackInfo != null) && (playbackInfo.getPlaybackType() == PlaybackInfo.PLAYBACK_TYPE_REMOTE);
+        return (playbackInfo != null)
+                && (playbackInfo.getPlaybackType() == PlaybackInfo.PLAYBACK_TYPE_REMOTE);
+    }
+
+    private void selectOrDeselectSubtitle(boolean select) {
+        if (!isInPlaybackState()) {
+            return;
+        }
+        if (select) {
+            if (mSubtitleTrackIndices.size() > 0) {
+                // Select first subtitle track
+                mSelectedTrackIndex = mSubtitleTrackIndices.get(0);
+                mMediaPlayer.selectTrack(mSelectedTrackIndex);
+                mSubtitleView.setVisibility(View.VISIBLE);
+            }
+        } else {
+            if (mSelectedTrackIndex != INVALID_TRACK_INDEX) {
+                mMediaPlayer.deselectTrack(mSelectedTrackIndex);
+                mSelectedTrackIndex = INVALID_TRACK_INDEX;
+                mSubtitleView.setVisibility(View.GONE);
+            }
+        }
+    }
+
+    private void extractSubtitleTracks() {
+        MediaPlayer.TrackInfo[] trackInfos = mMediaPlayer.getTrackInfo();
+        boolean previouslyNoTracks = mSubtitleTrackIndices == null
+                || mSubtitleTrackIndices.size() == 0;
+        mSubtitleTrackIndices = new ArrayList<>();
+        for (int i = 0; i < trackInfos.length; ++i) {
+            int trackType = trackInfos[i].getTrackType();
+            if (trackType == MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE
+                    || trackType == MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT) {
+                  mSubtitleTrackIndices.add(i);
+            }
+        }
+        if (mSubtitleTrackIndices.size() > 0) {
+            if (previouslyNoTracks) {
+                selectOrDeselectSubtitle(mSubtitleEnabled);
+                // Notify MediaControlView that subtitle track exists
+                // TODO: Send the subtitle track list to MediaSession for MCV2.
+                Bundle data = new Bundle();
+                data.putBoolean(MediaControlView2Impl.KEY_STATE_CONTAINS_SUBTITLE, true);
+                mMediaSession.sendSessionEvent(
+                        MediaControlView2Impl.EVENT_UPDATE_SUBTITLE_STATUS, data);
+            }
+        } else {
+            Bundle data = new Bundle();
+            data.putBoolean(MediaControlView2Impl.KEY_STATE_CONTAINS_SUBTITLE, false);
+            mMediaSession.sendSessionEvent(
+                    MediaControlView2Impl.EVENT_UPDATE_SUBTITLE_STATUS, data);
+        }
     }
 
     MediaPlayer.OnVideoSizeChangedListener mSizeChangedListener =
@@ -805,6 +843,7 @@
             mCurrentState = STATE_PREPARED;
             // Create and set playback state for MediaControlView2
             updatePlaybackState();
+            extractSubtitleTracks();
 
             if (mOnPreparedListener != null) {
                 mOnPreparedListener.onPrepared(mInstance);
@@ -884,6 +923,10 @@
                     if (mOnInfoListener != null) {
                         mOnInfoListener.onInfo(mInstance, what, extra);
                     }
+
+                    if (what == MediaPlayer.MEDIA_INFO_METADATA_UPDATE) {
+                        extractSubtitleTracks();
+                    }
                     return true;
                 }
             };
@@ -954,6 +997,15 @@
                 }
             };
 
+    // TODO: Remove timed text related code later once relevant Renderer is defined.
+    // This is just for debugging purpose.
+    private MediaPlayer.OnTimedTextListener mTimedTextListener =
+            new MediaPlayer.OnTimedTextListener() {
+                public void onTimedText(MediaPlayer mp, TimedText text) {
+                    Log.d(TAG, "TimedText: " + text.getText());
+                }
+            };
+
     private class MediaSessionCallback extends MediaSession.Callback {
         @Override
         public void onCommand(String command, Bundle args, ResultReceiver receiver) {
diff --git a/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java b/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java
index 4cd8177..eff4c3b 100644
--- a/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java
+++ b/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java
@@ -24,6 +24,7 @@
 import android.content.Context;
 import android.media.MediaBrowser2.BrowserCallback;
 import android.media.MediaSession2.Command;
+import android.media.MediaSession2.CommandButton;
 import android.media.MediaSession2.CommandGroup;
 import android.media.MediaSession2.PlaylistParams;
 import android.os.Bundle;
@@ -36,6 +37,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -104,42 +106,41 @@
         @CallSuper
         @Override
         public void onConnected(CommandGroup commands) {
-            super.onConnected(commands);
             connectLatch.countDown();
         }
 
         @CallSuper
         @Override
         public void onDisconnected() {
-            super.onDisconnected();
             disconnectLatch.countDown();
         }
 
         @Override
         public void onPlaybackStateChanged(PlaybackState2 state) {
-            super.onPlaybackStateChanged(state);
             mCallbackProxy.onPlaybackStateChanged(state);
         }
 
         @Override
         public void onPlaylistParamsChanged(PlaylistParams params) {
-            super.onPlaylistParamsChanged(params);
             mCallbackProxy.onPlaylistParamsChanged(params);
         }
 
         @Override
         public void onPlaybackInfoChanged(MediaController2.PlaybackInfo info) {
-            if (mCallbackProxy != null) {
-                mCallbackProxy.onPlaybackInfoChanged(info);
-            }
+            mCallbackProxy.onPlaybackInfoChanged(info);
         }
 
         @Override
         public void onCustomCommand(Command command, Bundle args, ResultReceiver receiver) {
-            super.onCustomCommand(command, args, receiver);
             mCallbackProxy.onCustomCommand(command, args, receiver);
         }
 
+
+        @Override
+        public void onCustomLayoutChanged(List<CommandButton> layout) {
+            mCallbackProxy.onCustomLayoutChanged(layout);
+        }
+
         @Override
         public void onGetRootResult(Bundle rootHints, String rootMediaId, Bundle rootExtra) {
             super.onGetRootResult(rootHints, rootMediaId, rootExtra);
diff --git a/packages/MediaComponents/test/src/android/media/MediaSession2Test.java b/packages/MediaComponents/test/src/android/media/MediaSession2Test.java
index b00633b..f5ac6aa 100644
--- a/packages/MediaComponents/test/src/android/media/MediaSession2Test.java
+++ b/packages/MediaComponents/test/src/android/media/MediaSession2Test.java
@@ -33,6 +33,8 @@
 import android.media.MediaPlayerInterface.PlaybackListener;
 import android.media.MediaSession2.Builder;
 import android.media.MediaSession2.Command;
+import android.media.MediaSession2.CommandButton;
+import android.media.MediaSession2.CommandGroup;
 import android.media.MediaSession2.ControllerInfo;
 import android.media.MediaSession2.PlaylistParams;
 import android.media.MediaSession2.SessionCallback;
@@ -353,6 +355,45 @@
     }
 
     @Test
+    public void testSetCustomLayout() throws InterruptedException {
+        final List<CommandButton> buttons = new ArrayList<>();
+        buttons.add(new CommandButton.Builder(mContext)
+                .setCommand(new Command(mContext, MediaSession2.COMMAND_CODE_PLAYBACK_PLAY))
+                .setDisplayName("button").build());
+        final CountDownLatch latch = new CountDownLatch(1);
+        final SessionCallback sessionCallback = new SessionCallback(mContext) {
+            @Override
+            public CommandGroup onConnect(ControllerInfo controller) {
+                if (mContext.getPackageName().equals(controller.getPackageName())) {
+                    mSession.setCustomLayout(controller, buttons);
+                }
+                return super.onConnect(controller);
+            }
+        };
+
+        try (final MediaSession2 session = new MediaSession2.Builder(mContext, mPlayer)
+                .setId("testSetCustomLayout")
+                .setSessionCallback(sHandlerExecutor, sessionCallback)
+                .build()) {
+            final TestControllerCallbackInterface callback = new TestControllerCallbackInterface() {
+                @Override
+                public void onCustomLayoutChanged(List<CommandButton> layout) {
+                    assertEquals(layout.size(), buttons.size());
+                    for (int i = 0; i < layout.size(); i++) {
+                        assertEquals(layout.get(i).getCommand(), buttons.get(i).getCommand());
+                        assertEquals(layout.get(i).getDisplayName(),
+                                buttons.get(i).getDisplayName());
+                    }
+                    latch.countDown();
+                }
+            };
+            final MediaController2 controller =
+                    createController(session.getToken(), true, callback);
+            assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        }
+    }
+
+    @Test
     public void testSendCustomAction() throws InterruptedException {
         final Command testCommand =
                 new Command(mContext, MediaSession2.COMMAND_CODE_PLAYBACK_PREPARE);
diff --git a/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java b/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java
index 513fa29..f5abfff 100644
--- a/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java
+++ b/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.media.MediaController2.ControllerCallback;
 import android.media.MediaSession2.Command;
+import android.media.MediaSession2.CommandButton;
 import android.media.MediaSession2.CommandGroup;
 import android.os.Bundle;
 import android.os.HandlerThread;
@@ -59,15 +60,15 @@
         ControllerCallback getCallback();
     }
 
+    // Any change here should be also reflected to the TestControllerCallback and
+    // TestBrowserCallback
     interface TestControllerCallbackInterface {
-        // Add methods in ControllerCallback/BrowserCallback that you want to test.
+        // Add methods in ControllerCallback that you want to test.
         default void onPlaylistChanged(List<MediaItem2> playlist) {}
         default void onPlaylistParamsChanged(MediaSession2.PlaylistParams params) {}
         default void onPlaybackInfoChanged(MediaController2.PlaybackInfo info) {}
-
-        // Currently empty. Add methods in ControllerCallback/BrowserCallback that you want to test.
-        default void onPlaybackStateChanged(PlaybackState2 state) { }
-
+        default void onPlaybackStateChanged(PlaybackState2 state) {}
+        default void onCustomLayoutChanged(List<CommandButton> layout) {}
         default void onCustomCommand(Command command, Bundle args, ResultReceiver receiver) {}
     }
 
@@ -188,26 +189,22 @@
         @CallSuper
         @Override
         public void onConnected(CommandGroup commands) {
-            super.onConnected(commands);
             connectLatch.countDown();
         }
 
         @CallSuper
         @Override
         public void onDisconnected() {
-            super.onDisconnected();
             disconnectLatch.countDown();
         }
 
         @Override
         public void onPlaybackStateChanged(PlaybackState2 state) {
-            super.onPlaybackStateChanged(state);
             mCallbackProxy.onPlaybackStateChanged(state);
         }
 
         @Override
         public void onCustomCommand(Command command, Bundle args, ResultReceiver receiver) {
-            super.onCustomCommand(command, args, receiver);
             mCallbackProxy.onCustomCommand(command, args, receiver);
         }
 
@@ -231,23 +228,22 @@
 
         @Override
         public void onPlaylistChanged(List<MediaItem2> params) {
-            if (mCallbackProxy != null) {
-                mCallbackProxy.onPlaylistChanged(params);
-            }
+            mCallbackProxy.onPlaylistChanged(params);
         }
 
         @Override
         public void onPlaylistParamsChanged(MediaSession2.PlaylistParams params) {
-            if (mCallbackProxy != null) {
-                mCallbackProxy.onPlaylistParamsChanged(params);
-            }
+            mCallbackProxy.onPlaylistParamsChanged(params);
         }
 
         @Override
         public void onPlaybackInfoChanged(MediaController2.PlaybackInfo info) {
-            if (mCallbackProxy != null) {
-                mCallbackProxy.onPlaybackInfoChanged(info);
-            }
+            mCallbackProxy.onPlaybackInfoChanged(info);
+        }
+
+        @Override
+        public void onCustomLayoutChanged(List<CommandButton> layout) {
+            mCallbackProxy.onCustomLayoutChanged(layout);
         }
     }
 
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index e7140c2..a3ce1f6 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -321,6 +321,7 @@
                                               actualSessionId,
                                               client.clientPid,
                                               client.clientUid,
+                                              client.packageName,
                                               config,
                                               AUDIO_INPUT_FLAG_MMAP_NOIRQ, deviceId, &portId);
     }
@@ -340,7 +341,7 @@
         if (direction == MmapStreamInterface::DIRECTION_OUTPUT) {
             AudioSystem::releaseOutput(io, streamType, actualSessionId);
         } else {
-            AudioSystem::releaseInput(io, actualSessionId);
+            AudioSystem::releaseInput(portId);
         }
         ret = NO_INIT;
     }
@@ -658,7 +659,7 @@
     sp<Client> client;
     status_t lStatus;
     audio_stream_type_t streamType;
-    audio_port_handle_t portId;
+    audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
 
     bool updatePid = (input.clientInfo.clientPid == -1);
     const uid_t callingUid = IPCThreadState::self()->getCallingUid();
@@ -1596,7 +1597,7 @@
     sp<Client> client;
     status_t lStatus;
     audio_session_t sessionId = input.sessionId;
-    audio_port_handle_t portId;
+    audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
 
     output.cblk.clear();
     output.buffers.clear();
@@ -1621,12 +1622,6 @@
         clientPid = callingPid;
     }
 
-    // check calling permissions
-    if (!recordingAllowed(input.opPackageName, input.clientInfo.clientTid, clientUid)) {
-        ALOGE("createRecord() permission denied: recording not allowed");
-        lStatus = PERMISSION_DENIED;
-        goto Exit;
-    }
     // we don't yet support anything other than linear PCM
     if (!audio_is_valid_format(input.config.format) || !audio_is_linear_pcm(input.config.format)) {
         ALOGE("createRecord() invalid format %#x", input.config.format);
@@ -1663,14 +1658,16 @@
     // release previously opened input if retrying.
     if (output.inputId != AUDIO_IO_HANDLE_NONE) {
         recordTrack.clear();
-        AudioSystem::releaseInput(output.inputId, sessionId);
+        AudioSystem::releaseInput(portId);
         output.inputId = AUDIO_IO_HANDLE_NONE;
+        portId = AUDIO_PORT_HANDLE_NONE;
     }
     lStatus = AudioSystem::getInputForAttr(&input.attr, &output.inputId,
                                       sessionId,
                                     // FIXME compare to AudioTrack
                                       clientPid,
                                       clientUid,
+                                      input.opPackageName,
                                       &input.config,
                                       output.flags, &output.selectedDeviceId, &portId);
 
@@ -1739,7 +1736,7 @@
         }
         recordTrack.clear();
         if (output.inputId != AUDIO_IO_HANDLE_NONE) {
-            AudioSystem::releaseInput(output.inputId, sessionId);
+            AudioSystem::releaseInput(portId);
         }
     }
 
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 24d862f..d6021b3 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -6936,8 +6936,7 @@
         if (recordTrack->isExternalTrack()) {
             mLock.unlock();
             bool silenced;
-            status = AudioSystem::startInput(mId, recordTrack->sessionId(),
-                    mInDevice, recordTrack->uid(), &silenced);
+            status = AudioSystem::startInput(recordTrack->portId(), &silenced);
             mLock.lock();
             // FIXME should verify that recordTrack is still in mActiveTracks
             if (status != NO_ERROR) {
@@ -6969,7 +6968,7 @@
 
 startError:
     if (recordTrack->isExternalTrack()) {
-        AudioSystem::stopInput(mId, recordTrack->sessionId());
+        AudioSystem::stopInput(recordTrack->portId());
     }
     recordTrack->clearSyncStartEvent();
     // FIXME I wonder why we do not reset the state here?
@@ -7785,7 +7784,7 @@
     if (isOutput()) {
         AudioSystem::releaseOutput(mId, streamType(), mSessionId);
     } else {
-        AudioSystem::releaseInput(mId, mSessionId);
+        AudioSystem::releaseInput(mPortId);
     }
 }
 
@@ -7845,10 +7844,6 @@
         return NO_ERROR;
     }
 
-    if (!isOutput() && !recordingAllowed(client.packageName, client.clientPid, client.clientUid)) {
-        return PERMISSION_DENIED;
-    }
-
     audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
 
     audio_io_handle_t io = mId;
@@ -7880,6 +7875,7 @@
                                               mSessionId,
                                               client.clientPid,
                                               client.clientUid,
+                                              client.packageName,
                                               &config,
                                               AUDIO_INPUT_FLAG_MMAP_NOIRQ,
                                               &deviceId,
@@ -7898,7 +7894,7 @@
     } else {
         // TODO: Block recording for idle UIDs (b/72134552)
         bool silenced;
-        ret = AudioSystem::startInput(mId, mSessionId, mInDevice, client.clientUid, &silenced);
+        ret = AudioSystem::startInput(portId, &silenced);
     }
 
     // abort if start is rejected by audio policy manager
@@ -7908,7 +7904,7 @@
             if (isOutput()) {
                 AudioSystem::releaseOutput(mId, streamType(), mSessionId);
             } else {
-                AudioSystem::releaseInput(mId, mSessionId);
+                AudioSystem::releaseInput(portId);
             }
         } else {
             mHalStream->stop();
@@ -7965,8 +7961,8 @@
         AudioSystem::stopOutput(mId, streamType(), track->sessionId());
         AudioSystem::releaseOutput(mId, streamType(), track->sessionId());
     } else {
-        AudioSystem::stopInput(mId, track->sessionId());
-        AudioSystem::releaseInput(mId, track->sessionId());
+        AudioSystem::stopInput(track->portId());
+        AudioSystem::releaseInput(track->portId());
     }
 
     sp<EffectChain> chain = getEffectChain_l(track->sessionId());
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index ce5c53b..67f27d0 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1694,7 +1694,7 @@
     if (thread != 0) {
         RecordThread *recordThread = (RecordThread *)thread.get();
         if (recordThread->stop(this) && isExternalTrack()) {
-            AudioSystem::stopInput(mThreadIoHandle, mSessionId);
+            AudioSystem::stopInput(mPortId);
         }
     }
 }
@@ -1706,9 +1706,9 @@
     {
         if (isExternalTrack()) {
             if (mState == ACTIVE || mState == RESUMING) {
-                AudioSystem::stopInput(mThreadIoHandle, mSessionId);
+                AudioSystem::stopInput(mPortId);
             }
-            AudioSystem::releaseInput(mThreadIoHandle, mSessionId);
+            AudioSystem::releaseInput(mPortId);
         }
         sp<ThreadBase> thread = mThread.promote();
         if (thread != 0) {
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index f1d7d86..306de3f 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -287,6 +287,7 @@
                                              audio_session_t session,
                                              pid_t pid,
                                              uid_t uid,
+                                             const String16& opPackageName,
                                              const audio_config_base_t *config,
                                              audio_input_flags_t flags,
                                              audio_port_handle_t *selectedDeviceId,
@@ -295,6 +296,7 @@
     if (mAudioPolicyManager == NULL) {
         return NO_INIT;
     }
+
     // already checked by client, but double-check in case the client wrapper is bypassed
     if (attr->source < AUDIO_SOURCE_DEFAULT && attr->source >= AUDIO_SOURCE_CNT &&
             attr->source != AUDIO_SOURCE_HOTWORD && attr->source != AUDIO_SOURCE_FM_TUNER) {
@@ -318,6 +320,13 @@
         pid = callingPid;
     }
 
+    // check calling permissions
+    if (!recordingAllowed(opPackageName, pid, uid)) {
+        ALOGE("%s permission denied: recording not allowed for uid %d pid %d",
+                __func__, uid, pid);
+        return PERMISSION_DENIED;
+    }
+
     if ((attr->source == AUDIO_SOURCE_HOTWORD) && !captureHotwordAllowed(pid, uid)) {
         return BAD_VALUE;
     }
@@ -367,6 +376,13 @@
             }
             return status;
         }
+
+        sp<AudioRecordClient> client =
+                new AudioRecordClient(*attr, *input, uid, pid, opPackageName, session);
+        client->active = false;
+        client->isConcurrent = false;
+        client->isVirtualDevice = false; //TODO : update from APM->getInputForAttr()
+        mAudioRecordClients.add(*portId, client);
     }
 
     if (audioPolicyEffects != 0) {
@@ -379,23 +395,38 @@
     return NO_ERROR;
 }
 
-status_t AudioPolicyService::startInput(audio_io_handle_t input,
-                                        audio_session_t session,
-                                        audio_devices_t device,
-                                        uid_t uid,
-                                        bool *silenced)
+status_t AudioPolicyService::startInput(audio_port_handle_t portId, bool *silenced)
 {
-    // If UID inactive it records silence until becoming active
-    *silenced = !mUidPolicy->isUidActive(uid) && !is_virtual_input_device(device);
-
     if (mAudioPolicyManager == NULL) {
         return NO_INIT;
     }
+    sp<AudioRecordClient> client;
+    {
+        Mutex::Autolock _l(mLock);
+
+        ssize_t index = mAudioRecordClients.indexOfKey(portId);
+        if (index < 0) {
+            return INVALID_OPERATION;
+        }
+        client = mAudioRecordClients.valueAt(index);
+    }
+
+    // check calling permissions
+    if (!recordingAllowed(client->opPackageName, client->pid, client->uid)) {
+        ALOGE("%s permission denied: recording not allowed for uid %d pid %d",
+                __func__, client->uid, client->pid);
+        return PERMISSION_DENIED;
+    }
+
+    // If UID inactive it records silence until becoming active
+    *silenced = !mUidPolicy->isUidActive(client->uid) && !client->isVirtualDevice;
 
     Mutex::Autolock _l(mLock);
     AudioPolicyInterface::concurrency_type__mask_t concurrency =
             AudioPolicyInterface::API_INPUT_CONCURRENCY_NONE;
-    status_t status = mAudioPolicyManager->startInput(input, session, *silenced, &concurrency);
+
+    status_t status = mAudioPolicyManager->startInput(
+            client->input, client->session, *silenced, &concurrency);
 
     if (status == NO_ERROR) {
         LOG_ALWAYS_FATAL_IF(concurrency & ~AudioPolicyInterface::API_INPUT_CONCURRENCY_ALL,
@@ -413,38 +444,52 @@
     return status;
 }
 
-status_t AudioPolicyService::stopInput(audio_io_handle_t input,
-                                       audio_session_t session)
+status_t AudioPolicyService::stopInput(audio_port_handle_t portId)
 {
     if (mAudioPolicyManager == NULL) {
         return NO_INIT;
     }
     Mutex::Autolock _l(mLock);
 
-    return mAudioPolicyManager->stopInput(input, session);
+    ssize_t index = mAudioRecordClients.indexOfKey(portId);
+    if (index < 0) {
+        return INVALID_OPERATION;
+    }
+    sp<AudioRecordClient> client = mAudioRecordClients.valueAt(index);
+
+    return mAudioPolicyManager->stopInput(client->input, client->session);
 }
 
-void AudioPolicyService::releaseInput(audio_io_handle_t input,
-                                      audio_session_t session)
+void AudioPolicyService::releaseInput(audio_port_handle_t portId)
 {
     if (mAudioPolicyManager == NULL) {
         return;
     }
     sp<AudioPolicyEffects>audioPolicyEffects;
+    sp<AudioRecordClient> client;
     {
         Mutex::Autolock _l(mLock);
         audioPolicyEffects = mAudioPolicyEffects;
+        ssize_t index = mAudioRecordClients.indexOfKey(portId);
+        if (index < 0) {
+            return;
+        }
+        client = mAudioRecordClients.valueAt(index);
+        mAudioRecordClients.removeItem(portId);
+    }
+    if (client == 0) {
+        return;
     }
     if (audioPolicyEffects != 0) {
         // release audio processors from the input
-        status_t status = audioPolicyEffects->releaseInputEffects(input, session);
+        status_t status = audioPolicyEffects->releaseInputEffects(client->input, client->session);
         if(status != NO_ERROR) {
-            ALOGW("Failed to release effects on input %d", input);
+            ALOGW("Failed to release effects on input %d", client->input);
         }
     }
     {
         Mutex::Autolock _l(mLock);
-        mAudioPolicyManager->releaseInput(input, session);
+        mAudioPolicyManager->releaseInput(client->input, client->session);
     }
 }
 
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index c21aa58..bfa3ef4 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -98,19 +98,15 @@
                                      audio_session_t session,
                                      pid_t pid,
                                      uid_t uid,
+                                     const String16& opPackageName,
                                      const audio_config_base_t *config,
                                      audio_input_flags_t flags,
                                      audio_port_handle_t *selectedDeviceId = NULL,
                                      audio_port_handle_t *portId = NULL);
-    virtual status_t startInput(audio_io_handle_t input,
-                                audio_session_t session,
-                                audio_devices_t device,
-                                uid_t uid,
+    virtual status_t startInput(audio_port_handle_t portId,
                                 bool *silenced);
-    virtual status_t stopInput(audio_io_handle_t input,
-                               audio_session_t session);
-    virtual void releaseInput(audio_io_handle_t input,
-                              audio_session_t session);
+    virtual status_t stopInput(audio_port_handle_t portId);
+    virtual void releaseInput(audio_port_handle_t portId);
     virtual status_t initStreamVolume(audio_stream_type_t stream,
                                       int indexMin,
                                       int indexMax);
@@ -611,6 +607,31 @@
               bool                          mAudioPortCallbacksEnabled;
     };
 
+    // --- AudioRecordClient ---
+    // Information about each registered AudioRecord client
+    // (between calls to getInputForAttr() and releaseInput())
+    class AudioRecordClient : public RefBase {
+    public:
+                AudioRecordClient(const audio_attributes_t attributes,
+                                  const audio_io_handle_t input, uid_t uid, pid_t pid,
+                                  const String16& opPackageName, const audio_session_t session) :
+                                      attributes(attributes),
+                                      input(input), uid(uid), pid(pid),
+                                      opPackageName(opPackageName), session(session),
+                                      active(false), isConcurrent(false), isVirtualDevice(false) {}
+        virtual ~AudioRecordClient() {}
+
+        const audio_attributes_t attributes; // source, flags ...
+        const audio_io_handle_t input;       // audio HAL input IO handle
+        const uid_t uid;                     // client UID
+        const pid_t pid;                     // client PID
+        const String16 opPackageName;        // client package name
+        const audio_session_t session;       // audio session ID
+        bool active;                   // Capture is active or inactive
+        bool isConcurrent;             // is allowed to concurrent capture
+        bool isVirtualDevice;          // uses vitual device: updated by APM::getInputForAttr()
+    };
+
     // Internal dump utilities.
     status_t dumpPermissionDenial(int fd);
 
@@ -636,6 +657,7 @@
     audio_mode_t mPhoneState;
 
     sp<UidPolicy> mUidPolicy;
+    DefaultKeyedVector< audio_port_handle_t, sp<AudioRecordClient> >   mAudioRecordClients;
 };
 
 } // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 324201b..59bb2e2 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -676,8 +676,6 @@
             "TEMPLATE_VIDEO_SNAPSHOT",
             "TEMPLATE_ZERO_SHUTTER_LAG",
             "TEMPLATE_MANUAL",
-            "TEMPLATE_MOTION_TRACKING_PREVIEW",
-            "TEMPALTE_MOTION_TRACKING_BEST"
         };
 
         for (int i = 1; i < CAMERA3_TEMPLATE_COUNT; i++) {
@@ -3435,65 +3433,31 @@
             }
         };
     hardware::Return<void> err;
-    if (mHidlSession_3_4 != nullptr) {
-        device::V3_4::RequestTemplate id;
-        switch (templateId) {
-            case CAMERA3_TEMPLATE_PREVIEW:
-                id = device::V3_4::RequestTemplate::PREVIEW;
-                break;
-            case CAMERA3_TEMPLATE_STILL_CAPTURE:
-                id = device::V3_4::RequestTemplate::STILL_CAPTURE;
-                break;
-            case CAMERA3_TEMPLATE_VIDEO_RECORD:
-                id = device::V3_4::RequestTemplate::VIDEO_RECORD;
-                break;
-            case CAMERA3_TEMPLATE_VIDEO_SNAPSHOT:
-                id = device::V3_4::RequestTemplate::VIDEO_SNAPSHOT;
-                break;
-            case CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG:
-                id = device::V3_4::RequestTemplate::ZERO_SHUTTER_LAG;
-                break;
-            case CAMERA3_TEMPLATE_MANUAL:
-                id = device::V3_4::RequestTemplate::MANUAL;
-                break;
-            case CAMERA3_TEMPLATE_MOTION_TRACKING_PREVIEW:
-                id = device::V3_4::RequestTemplate::MOTION_TRACKING_PREVIEW;
-                break;
-            case CAMERA3_TEMPLATE_MOTION_TRACKING_BEST:
-                id = device::V3_4::RequestTemplate::MOTION_TRACKING_BEST;
-                break;
-            default:
-                // Unknown template ID
-                return BAD_VALUE;
-        }
-        err = mHidlSession_3_4->constructDefaultRequestSettings_3_4(id, requestCallback);
-    } else {
-        RequestTemplate id;
-        switch (templateId) {
-            case CAMERA3_TEMPLATE_PREVIEW:
-                id = RequestTemplate::PREVIEW;
-                break;
-            case CAMERA3_TEMPLATE_STILL_CAPTURE:
-                id = RequestTemplate::STILL_CAPTURE;
-                break;
-            case CAMERA3_TEMPLATE_VIDEO_RECORD:
-                id = RequestTemplate::VIDEO_RECORD;
-                break;
-            case CAMERA3_TEMPLATE_VIDEO_SNAPSHOT:
-                id = RequestTemplate::VIDEO_SNAPSHOT;
-                break;
-            case CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG:
-                id = RequestTemplate::ZERO_SHUTTER_LAG;
-                break;
-            case CAMERA3_TEMPLATE_MANUAL:
-                id = RequestTemplate::MANUAL;
-                break;
-            default:
-                // Unknown template ID, or this HAL is too old to support it
-                return BAD_VALUE;
-        }
-        err = mHidlSession->constructDefaultRequestSettings(id, requestCallback);
+    RequestTemplate id;
+    switch (templateId) {
+        case CAMERA3_TEMPLATE_PREVIEW:
+            id = RequestTemplate::PREVIEW;
+            break;
+        case CAMERA3_TEMPLATE_STILL_CAPTURE:
+            id = RequestTemplate::STILL_CAPTURE;
+            break;
+        case CAMERA3_TEMPLATE_VIDEO_RECORD:
+            id = RequestTemplate::VIDEO_RECORD;
+            break;
+        case CAMERA3_TEMPLATE_VIDEO_SNAPSHOT:
+            id = RequestTemplate::VIDEO_SNAPSHOT;
+            break;
+        case CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG:
+            id = RequestTemplate::ZERO_SHUTTER_LAG;
+            break;
+        case CAMERA3_TEMPLATE_MANUAL:
+            id = RequestTemplate::MANUAL;
+            break;
+        default:
+            // Unknown template ID, or this HAL is too old to support it
+            return BAD_VALUE;
     }
+    err = mHidlSession->constructDefaultRequestSettings(id, requestCallback);
 
     if (!err.isOk()) {
         ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());