Merge "Write Exif data block for HEIF files" into pi-dev
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 39ee437..c072901 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -1286,6 +1286,24 @@
     return af->getMicrophones(microphones);
 }
 
+status_t AudioSystem::getSurroundFormats(unsigned int *numSurroundFormats,
+                                         audio_format_t *surroundFormats,
+                                         bool *surroundFormatsEnabled,
+                                         bool reported)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->getSurroundFormats(
+            numSurroundFormats, surroundFormats, surroundFormatsEnabled, reported);
+}
+
+status_t AudioSystem::setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->setSurroundFormatEnabled(audioFormat, enabled);
+}
+
 // ---------------------------------------------------------------------------
 
 int AudioSystem::AudioPolicyServiceClient::addAudioPortCallback(
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index eca6fee..a1236e7 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -80,7 +80,9 @@
     SET_AUDIO_PORT_CALLBACK_ENABLED,
     SET_MASTER_MONO,
     GET_MASTER_MONO,
-    GET_STREAM_VOLUME_DB
+    GET_STREAM_VOLUME_DB,
+    GET_SURROUND_FORMATS,
+    SET_SURROUND_FORMAT_ENABLED
 };
 
 #define MAX_ITEMS_PER_LIST 1024
@@ -829,6 +831,54 @@
         }
         return reply.readFloat();
     }
+
+    virtual status_t getSurroundFormats(unsigned int *numSurroundFormats,
+                                        audio_format_t *surroundFormats,
+                                        bool *surroundFormatsEnabled,
+                                        bool reported)
+    {
+        if (numSurroundFormats == NULL || (*numSurroundFormats != 0 &&
+                (surroundFormats == NULL || surroundFormatsEnabled == NULL))) {
+            return BAD_VALUE;
+        }
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        unsigned int numSurroundFormatsReq = *numSurroundFormats;
+        data.writeUint32(numSurroundFormatsReq);
+        data.writeBool(reported);
+        status_t status = remote()->transact(GET_SURROUND_FORMATS, data, &reply);
+        if (status == NO_ERROR && (status = (status_t)reply.readInt32()) == NO_ERROR) {
+            *numSurroundFormats = reply.readUint32();
+        }
+        if (status == NO_ERROR) {
+            if (numSurroundFormatsReq > *numSurroundFormats) {
+                numSurroundFormatsReq = *numSurroundFormats;
+            }
+            if (numSurroundFormatsReq > 0) {
+                status = reply.read(surroundFormats,
+                                    numSurroundFormatsReq * sizeof(audio_format_t));
+                if (status != NO_ERROR) {
+                    return status;
+                }
+                status = reply.read(surroundFormatsEnabled,
+                                    numSurroundFormatsReq * sizeof(bool));
+            }
+        }
+        return status;
+    }
+
+    virtual status_t setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.writeInt32(audioFormat);
+        data.writeBool(enabled);
+        status_t status = remote()->transact(SET_SURROUND_FORMAT_ENABLED, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        return reply.readInt32();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService");
@@ -883,7 +933,9 @@
         case REGISTER_POLICY_MIXES:
         case SET_MASTER_MONO:
         case START_AUDIO_SOURCE:
-        case STOP_AUDIO_SOURCE: {
+        case STOP_AUDIO_SOURCE:
+        case GET_SURROUND_FORMATS:
+        case SET_SURROUND_FORMAT_ENABLED: {
             if (multiuser_get_app_id(IPCThreadState::self()->getCallingUid()) >= AID_APP_START) {
                 ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
                       __func__, code, IPCThreadState::self()->getCallingPid(),
@@ -1489,6 +1541,50 @@
             return NO_ERROR;
         }
 
+        case GET_SURROUND_FORMATS: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            unsigned int numSurroundFormatsReq = data.readUint32();
+            if (numSurroundFormatsReq > MAX_ITEMS_PER_LIST) {
+                numSurroundFormatsReq = MAX_ITEMS_PER_LIST;
+            }
+            bool reported = data.readBool();
+            unsigned int numSurroundFormats = numSurroundFormatsReq;
+            audio_format_t *surroundFormats = (audio_format_t *)calloc(
+                    numSurroundFormats, sizeof(audio_format_t));
+            bool *surroundFormatsEnabled = (bool *)calloc(numSurroundFormats, sizeof(bool));
+            if (numSurroundFormatsReq > 0 &&
+                    (surroundFormats == NULL || surroundFormatsEnabled == NULL)) {
+                free(surroundFormats);
+                free(surroundFormatsEnabled);
+                reply->writeInt32(NO_MEMORY);
+                return NO_ERROR;
+            }
+            status_t status = getSurroundFormats(
+                    &numSurroundFormats, surroundFormats, surroundFormatsEnabled, reported);
+            reply->writeInt32(status);
+
+            if (status == NO_ERROR) {
+                reply->writeUint32(numSurroundFormats);
+                if (numSurroundFormatsReq > numSurroundFormats) {
+                    numSurroundFormatsReq = numSurroundFormats;
+                }
+                reply->write(surroundFormats, numSurroundFormatsReq * sizeof(audio_format_t));
+                reply->write(surroundFormatsEnabled, numSurroundFormatsReq * sizeof(bool));
+            }
+            free(surroundFormats);
+            free(surroundFormatsEnabled);
+            return NO_ERROR;
+        }
+
+        case SET_SURROUND_FORMAT_ENABLED: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            audio_format_t audioFormat = (audio_format_t) data.readInt32();
+            bool enabled = data.readBool();
+            status_t status = setSurroundFormatEnabled(audioFormat, enabled);
+            reply->writeInt32(status);
+            return NO_ERROR;
+        }
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libaudioclient/include/media/AudioParameter.h b/media/libaudioclient/include/media/AudioParameter.h
index 59ac1db..967d895 100644
--- a/media/libaudioclient/include/media/AudioParameter.h
+++ b/media/libaudioclient/include/media/AudioParameter.h
@@ -81,6 +81,11 @@
 
     static const char * const valueListSeparator;
 
+    // keyReconfigA2dp: Ask HwModule to reconfigure A2DP offloaded codec
+    // keyReconfigA2dpSupported: Query if HwModule supports A2DP offload codec config
+    static const char * const keyReconfigA2dp;
+    static const char * const keyReconfigA2dpSupported;
+
     String8 toString() const { return toStringImpl(true); }
     String8 keysToString() const { return toStringImpl(false); }
 
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 0c4d6ee..4c0f796 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -340,6 +340,15 @@
 
     static status_t getMicrophones(std::vector<media::MicrophoneInfo> *microphones);
 
+    // numSurroundFormats holds the maximum number of formats and bool value allowed in the array.
+    // When numSurroundFormats is 0, surroundFormats and surroundFormatsEnabled will not be
+    // populated. The actual number of surround formats should be returned at numSurroundFormats.
+    static status_t getSurroundFormats(unsigned int *numSurroundFormats,
+                                       audio_format_t *surroundFormats,
+                                       bool *surroundFormatsEnabled,
+                                       bool reported);
+    static status_t setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled);
+
     // ----------------------------------------------------------------------------
 
     class AudioPortCallback : public RefBase
diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h
index 1114eeb..c3876af 100644
--- a/media/libaudioclient/include/media/IAudioPolicyService.h
+++ b/media/libaudioclient/include/media/IAudioPolicyService.h
@@ -166,6 +166,12 @@
     virtual status_t getMasterMono(bool *mono) = 0;
     virtual float    getStreamVolumeDB(
             audio_stream_type_t stream, int index, audio_devices_t device) = 0;
+
+    virtual status_t getSurroundFormats(unsigned int *numSurroundFormats,
+                                        audio_format_t *surroundFormats,
+                                        bool *surroundFormatsEnabled,
+                                        bool reported) = 0;
+    virtual status_t setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled) = 0;
 };
 
 
diff --git a/media/libeffects/config/Android.bp b/media/libeffects/config/Android.bp
index 3e88c7c..5fa9da9 100644
--- a/media/libeffects/config/Android.bp
+++ b/media/libeffects/config/Android.bp
@@ -1,5 +1,5 @@
 // Effect configuration
-cc_library_shared {
+cc_library {
     name: "libeffectsconfig",
     vendor_available: true,
 
diff --git a/media/libmedia/AudioParameter.cpp b/media/libmedia/AudioParameter.cpp
index cb0e927..034f7c2 100644
--- a/media/libmedia/AudioParameter.cpp
+++ b/media/libmedia/AudioParameter.cpp
@@ -47,6 +47,8 @@
 const char * const AudioParameter::valueOn = AUDIO_PARAMETER_VALUE_ON;
 const char * const AudioParameter::valueOff = AUDIO_PARAMETER_VALUE_OFF;
 const char * const AudioParameter::valueListSeparator = AUDIO_PARAMETER_VALUE_LIST_SEPARATOR;
+const char * const AudioParameter::keyReconfigA2dp = AUDIO_PARAMETER_RECONFIG_A2DP;
+const char * const AudioParameter::keyReconfigA2dpSupported = AUDIO_PARAMETER_A2DP_RECONFIG_SUPPORTED;
 
 AudioParameter::AudioParameter(const String8& keyValuePairs)
 {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 0a1bdfe..a5f5fc6 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -1447,6 +1447,29 @@
             break;
         }
 
+        case kWhatGetStats:
+        {
+            ALOGV("kWhatGetStats");
+
+            Vector<sp<AMessage>> *trackStats;
+            CHECK(msg->findPointer("trackstats", (void**)&trackStats));
+
+            trackStats->clear();
+            if (mVideoDecoder != NULL) {
+                trackStats->push_back(mVideoDecoder->getStats());
+            }
+            if (mAudioDecoder != NULL) {
+                trackStats->push_back(mAudioDecoder->getStats());
+            }
+
+            // respond for synchronization
+            sp<AMessage> response = new AMessage;
+            sp<AReplyToken> replyID;
+            CHECK(msg->senderAwaitsResponse(&replyID));
+            response->postReply(replyID);
+            break;
+        }
+
         default:
             TRESPASS();
             break;
@@ -2210,16 +2233,16 @@
     return renderer->getCurrentPosition(mediaUs);
 }
 
-void NuPlayer::getStats(Vector<sp<AMessage> > *mTrackStats) {
-    CHECK(mTrackStats != NULL);
+void NuPlayer::getStats(Vector<sp<AMessage> > *trackStats) {
+    CHECK(trackStats != NULL);
 
-    mTrackStats->clear();
-    if (mVideoDecoder != NULL) {
-        mTrackStats->push_back(mVideoDecoder->getStats());
-    }
-    if (mAudioDecoder != NULL) {
-        mTrackStats->push_back(mAudioDecoder->getStats());
-    }
+    ALOGV("NuPlayer::getStats()");
+    sp<AMessage> msg = new AMessage(kWhatGetStats, this);
+    msg->setPointer("trackstats", trackStats);
+
+    sp<AMessage> response;
+    (void) msg->postAndAwaitResponse(&response);
+    // response is for synchronization, ignore contents
 }
 
 sp<MetaData> NuPlayer::getFileMeta() {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 3a7ef4e..e400d16 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -88,7 +88,7 @@
     status_t getSelectedTrack(int32_t type, Parcel* reply) const;
     status_t selectTrack(size_t trackIndex, bool select, int64_t timeUs);
     status_t getCurrentPosition(int64_t *mediaUs);
-    void getStats(Vector<sp<AMessage> > *mTrackStats);
+    void getStats(Vector<sp<AMessage> > *trackStats);
 
     sp<MetaData> getFileMeta();
     float getFrameRate();
@@ -159,6 +159,7 @@
         kWhatPrepareDrm                 = 'pDrm',
         kWhatReleaseDrm                 = 'rDrm',
         kWhatMediaClockNotify           = 'mckN',
+        kWhatGetStats                   = 'gSts',
     };
 
     wp<NuPlayerDriver> mDriver;
diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp
index 738f066..43304aa 100644
--- a/media/libstagefright/foundation/AMessage.cpp
+++ b/media/libstagefright/foundation/AMessage.cpp
@@ -116,6 +116,7 @@
         default:
             break;
     }
+    item->mType = kTypeInt32; // clear type
 }
 
 #ifdef DUMP_STATS
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h
index 5acc6d6..85e4378 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h
@@ -437,6 +437,94 @@
 };
 
 /**
+ * Helper template that copy assigns an object of a specific type (member) in an
+ * AUnion.
+ *
+ * \param Flagger type flagger class (see AData)
+ * \param U AUnion object in which the member should be copy assigned
+ * \param Ts types to consider for the member
+ */
+template<typename Flagger, typename U, typename ...Ts>
+struct HIDE _AData_copy_assigner;
+
+/**
+ * Template specialization when there are still types to consider (T and rest)
+ */
+template<typename Flagger, typename U, typename T, typename ...Ts>
+struct HIDE _AData_copy_assigner<Flagger, U, T, Ts...> {
+    static bool assign(typename Flagger::type flags, U &dst, const U &src) {
+        static_assert(std::is_copy_constructible<T>::value, "T must be copy constructible");
+        // if we can delete as, we can also assign as
+        if (Flagger::canDeleteAs(flags, Flagger::flagFor((T*)0))) {
+            dst.template emplace<T>(src.template get<T>());
+            return true;
+        }
+        return _AData_copy_assigner<Flagger, U, Ts...>::assign(flags, dst, src);
+    }
+};
+
+/**
+ * Template specialization when there are no more types to consider.
+ */
+template<typename Flagger, typename U>
+struct HIDE _AData_copy_assigner<Flagger, U> {
+    inline static bool assign(typename Flagger::type, U &, const U &) {
+        return false;
+    }
+};
+
+/**
+ * Helper template that move assigns an object of a specific type (member) in an
+ * AUnion.
+ *
+ * \param Flagger type flagger class (see AData)
+ * \param U AUnion object in which the member should be copy assigned
+ * \param Ts types to consider for the member
+ */
+template<typename Flagger, typename U, typename ...Ts>
+struct HIDE _AData_move_assigner;
+
+/**
+ * Template specialization when there are still types to consider (T and rest)
+ */
+template<typename Flagger, typename U, typename T, typename ...Ts>
+struct HIDE _AData_move_assigner<Flagger, U, T, Ts...> {
+    template<typename V = T>
+    static typename std::enable_if<std::is_move_constructible<V>::value, bool>::type
+    assign(typename Flagger::type flags, U &dst, U &src) {
+        // if we can delete as, we can also assign as
+        if (Flagger::canDeleteAs(flags, Flagger::flagFor((T*)0))) {
+            dst.template emplace<T>(std::move(src.template get<T>()));
+            return true;
+        }
+        return _AData_move_assigner<Flagger, U, Ts...>::assign(flags, dst, src);
+    }
+
+    // Fall back to copy construction if T is not move constructible
+    template<typename V = T>
+    static typename std::enable_if<!std::is_move_constructible<V>::value, bool>::type
+    assign(typename Flagger::type flags, U &dst, U &src) {
+        static_assert(std::is_copy_constructible<T>::value, "T must be copy constructible");
+        // if we can delete as, we can also assign as
+        if (Flagger::canDeleteAs(flags, Flagger::flagFor((T*)0))) {
+            dst.template emplace<T>(src.template get<T>());
+            return true;
+        }
+        return _AData_move_assigner<Flagger, U, Ts...>::assign(flags, dst, src);
+    }
+};
+
+/**
+ * Template specialization when there are no more types to consider.
+ */
+template<typename Flagger, typename U>
+struct HIDE _AData_move_assigner<Flagger, U> {
+    inline static bool assign(typename Flagger::type, U &, U &) {
+        return false;
+    }
+};
+
+/**
  * Container that can store an arbitrary object of a set of specified types.
  *
  * This struct is an outer class that contains various inner classes based on desired type
@@ -657,6 +745,61 @@
         Custom() : base_t(Flagger::flagFor((void*)0)) { }
 
         /**
+         * Copy assignment operator.
+         */
+        Custom& operator=(const Custom &o) {
+            if (&o != this) {
+                if (this->used() && !this->clear()) {
+                    __builtin_trap();
+                }
+                if (o.used()) {
+                    if (_AData_copy_assigner<Flagger, data_t, Ts...>::assign(
+                            o.flags(), this->get(), o.get())) {
+                        this->setFlags(o.flags());
+                    } else {
+                        __builtin_trap();
+                    }
+                }
+            }
+            return *this;
+        }
+
+        /**
+         * Copy constructor.
+         */
+        Custom(const Custom &o) : Custom() {
+            *this = o;
+        }
+
+        /**
+         * Move assignment operator.
+         */
+        Custom& operator=(Custom &&o) {
+            if (&o != this) {
+                if (this->used() && !this->clear()) {
+                    __builtin_trap();
+                }
+                if (o.used()) {
+                    if (_AData_move_assigner<Flagger, data_t, Ts...>::assign(
+                            o.flags(), this->get(), o.get())) {
+                        this->setFlags(o.flags());
+                        o.clear();
+                    } else {
+                        __builtin_trap();
+                    }
+                }
+            }
+            return *this;
+        }
+
+        /**
+         * Move constructor.
+         */
+        Custom(Custom &&o) : Custom() {
+            *this = std::move(o);
+        }
+
+        /**
          * Removes the contained object, if any.
          */
         ~Custom() {
diff --git a/media/libstagefright/foundation/tests/AData_test.cpp b/media/libstagefright/foundation/tests/AData_test.cpp
index f014c25..2628a47 100644
--- a/media/libstagefright/foundation/tests/AData_test.cpp
+++ b/media/libstagefright/foundation/tests/AData_test.cpp
@@ -978,4 +978,63 @@
     }
 };
 
+TEST_F(ADataTest, AData_AssignmentTest) {
+    typedef AData<sp<ABuffer>, int32_t>::Basic Data;
+
+    sp<ABuffer> buf1 = new ABuffer((void *)"hello", 6);
+    wp<ABuffer> buf1w = buf1;
+
+    Data obj1;
+    obj1.set(buf1);
+    EXPECT_NE(buf1w.promote(), nullptr);
+    buf1.clear();
+    EXPECT_NE(buf1w.promote(), nullptr);
+    obj1.clear();
+    EXPECT_EQ(buf1w.promote(), nullptr);
+
+    buf1 = new ABuffer((void *)"again", 6);
+    buf1w = buf1;
+
+    obj1.set(buf1);
+    EXPECT_TRUE(obj1.used());
+    Data obj2 = obj1;
+
+    sp<ABuffer> buf2;
+    EXPECT_TRUE(obj2.find(&buf2));
+    EXPECT_EQ(buf2, buf1);
+    buf1.clear();
+    buf2.clear();
+    EXPECT_NE(buf1w.promote(), nullptr);
+    obj1.clear();
+    EXPECT_NE(buf1w.promote(), nullptr);
+    obj2.clear();
+    EXPECT_EQ(buf1w.promote(), nullptr);
+
+    buf1 = new ABuffer((void *)"still", 6);
+    buf1w = buf1;
+
+    obj1.set(buf1);
+    EXPECT_TRUE(obj1.used());
+    obj2 = std::move(obj1);
+    EXPECT_FALSE(obj1.used());
+
+    EXPECT_TRUE(obj2.find(&buf2));
+    EXPECT_EQ(buf2, buf1);
+    buf1.clear();
+    buf2.clear();
+    EXPECT_NE(buf1w.promote(), nullptr);
+    obj2.clear();
+    EXPECT_EQ(buf1w.promote(), nullptr);
+
+    typedef AData<sp<ABuffer>, std::unique_ptr<int32_t>>::Basic Data2;
+    Data2 obj3, obj4;
+
+    buf1 = new ABuffer((void *)"hence", 6);
+    obj3.set(buf1);
+    obj4 = std::move(obj3);
+    EXPECT_FALSE(obj3.used());
+    EXPECT_TRUE(obj4.find(&buf2));
+    EXPECT_EQ(buf2, buf1);
+}
+
 } // namespace android
diff --git a/media/mtp/MtpFfsHandle.cpp b/media/mtp/MtpFfsHandle.cpp
index 952b907..f25fc71 100644
--- a/media/mtp/MtpFfsHandle.cpp
+++ b/media/mtp/MtpFfsHandle.cpp
@@ -127,27 +127,45 @@
     mControl.reset();
 }
 
-int MtpFfsHandle::doAsync(void* data, size_t len, bool read) {
-    struct io_event ioevs[1];
-    if (len > AIO_BUF_LEN) {
-        LOG(ERROR) << "Mtp read/write too large " << len;
-        errno = EINVAL;
-        return -1;
+int MtpFfsHandle::doAsync(void* data, size_t len, bool read, bool zero_packet) {
+    struct io_event ioevs[AIO_BUFS_MAX];
+    size_t total = 0;
+
+    while (total < len) {
+        size_t this_len = std::min(len - total, static_cast<size_t>(AIO_BUF_LEN * AIO_BUFS_MAX));
+        int num_bufs = this_len / AIO_BUF_LEN + (this_len % AIO_BUF_LEN == 0 ? 0 : 1);
+        for (int i = 0; i < num_bufs; i++) {
+            mIobuf[0].buf[i] = reinterpret_cast<unsigned char*>(data) + total + i * AIO_BUF_LEN;
+        }
+        int ret = iobufSubmit(&mIobuf[0], read ? mBulkOut : mBulkIn, this_len, read);
+        if (ret < 0) return -1;
+        ret = waitEvents(&mIobuf[0], ret, ioevs, nullptr);
+        if (ret < 0) return -1;
+        total += ret;
+        if (static_cast<size_t>(ret) < this_len) break;
     }
-    mIobuf[0].buf[0] = reinterpret_cast<unsigned char*>(data);
-    if (iobufSubmit(&mIobuf[0], read ? mBulkOut : mBulkIn, len, read) == -1)
-        return -1;
-    int ret = waitEvents(&mIobuf[0], 1, ioevs, nullptr);
-    mIobuf[0].buf[0] = mIobuf[0].bufs.data();
-    return ret;
+
+    int packet_size = getPacketSize(read ? mBulkOut : mBulkIn);
+    if (len % packet_size == 0 && zero_packet) {
+        int ret = iobufSubmit(&mIobuf[0], read ? mBulkOut : mBulkIn, 0, read);
+        if (ret < 0) return -1;
+        ret = waitEvents(&mIobuf[0], ret, ioevs, nullptr);
+        if (ret < 0) return -1;
+    }
+
+    for (unsigned i = 0; i < AIO_BUFS_MAX; i++) {
+        mIobuf[0].buf[i] = mIobuf[0].bufs.data() + i * AIO_BUF_LEN;
+    }
+    return total;
 }
 
 int MtpFfsHandle::read(void* data, size_t len) {
-    return doAsync(data, len, true);
+    // Zero packets are handled by receiveFile()
+    return doAsync(data, len, true, false);
 }
 
 int MtpFfsHandle::write(const void* data, size_t len) {
-    return doAsync(const_cast<void*>(data), len, false);
+    return doAsync(const_cast<void*>(data), len, false, true);
 }
 
 int MtpFfsHandle::handleEvent() {
@@ -570,7 +588,8 @@
     if (TEMP_FAILURE_RETRY(pread(mfr.fd, mIobuf[0].bufs.data() +
                     sizeof(mtp_data_header), init_read_len, offset))
             != init_read_len) return -1;
-    if (write(mIobuf[0].bufs.data(), sizeof(mtp_data_header) + init_read_len) == -1)
+    if (doAsync(mIobuf[0].bufs.data(), sizeof(mtp_data_header) + init_read_len,
+                false, false /* zlps are handled below */) == -1)
         return -1;
     file_length -= init_read_len;
     offset += init_read_len;
diff --git a/media/mtp/MtpFfsHandle.h b/media/mtp/MtpFfsHandle.h
index 24a8bd5..fe343f7 100644
--- a/media/mtp/MtpFfsHandle.h
+++ b/media/mtp/MtpFfsHandle.h
@@ -48,7 +48,7 @@
     void closeEndpoints();
     void advise(int fd);
     int handleControlRequest(const struct usb_ctrlrequest *request);
-    int doAsync(void* data, size_t len, bool read);
+    int doAsync(void* data, size_t len, bool read, bool zero_packet);
     int handleEvent();
     void cancelTransaction();
     void doSendEvent(mtp_event me);
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 86d59dd..ccddd6e 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -809,7 +809,7 @@
     uint64_t finalsize = sstat.st_size;
     ALOGV("Sent a file over MTP. Time: %f s, Size: %" PRIu64 ", Rate: %f bytes/s",
             diff.count(), finalsize, ((double) finalsize) / diff.count());
-    close(mfr.fd);
+    closeObjFd(mfr.fd, filePath);
     return result;
 }
 
@@ -887,7 +887,7 @@
         else
             result = MTP_RESPONSE_GENERAL_ERROR;
     }
-    close(mfr.fd);
+    closeObjFd(mfr.fd, filePath);
     return result;
 }
 
@@ -1043,7 +1043,7 @@
 
     if (info.mStorageID == storageID) {
         ALOGV("Moving file from %s to %s", (const char*)fromPath, (const char*)path);
-        if (rename(fromPath, path)) {
+        if (renameTo(fromPath, path)) {
             PLOG(ERROR) << "rename() failed from " << fromPath << " to " << path;
             result = MTP_RESPONSE_GENERAL_ERROR;
         }
@@ -1226,7 +1226,7 @@
     }
 
     fstat(mfr.fd, &sstat);
-    close(mfr.fd);
+    closeObjFd(mfr.fd, mSendObjectFilePath);
 
     if (ret < 0) {
         ALOGE("Mtp receive file got error %s", strerror(errno));
diff --git a/media/mtp/MtpUtils.cpp b/media/mtp/MtpUtils.cpp
index 51cfd7d..8564576 100644
--- a/media/mtp/MtpUtils.cpp
+++ b/media/mtp/MtpUtils.cpp
@@ -36,6 +36,13 @@
 
 constexpr unsigned long FILE_COPY_SIZE = 262144;
 
+static void access_ok(const char *path) {
+    if (access(path, F_OK) == -1) {
+        // Ignore. Failure could be common in cases of delete where
+        // the metadata was updated through other paths.
+    }
+}
+
 /*
 DateTime strings follow a compatible subset of the definition found in ISO 8601, and
 take the form of a Unicode string formatted as: "YYYYMMDDThhmmss.s". In this
@@ -101,6 +108,7 @@
     } else {
         chown((const char *)path, getuid(), FILE_GROUP);
     }
+    access_ok(path);
     return ret;
 }
 
@@ -181,6 +189,7 @@
     LOG(DEBUG) << "Copied a file with MTP. Time: " << diff.count() << " s, Size: " << length <<
         ", Rate: " << ((double) length) / diff.count() << " bytes/s";
     chown(toPath, getuid(), FILE_GROUP);
+    access_ok(toPath);
     return ret == -1 ? -1 : 0;
 }
 
@@ -212,6 +221,7 @@
         } else {
             success = unlink(childPath.c_str());
         }
+        access_ok(childPath.c_str());
         if (success == -1)
             PLOG(ERROR) << "Deleting path " << childPath << " failed";
     }
@@ -236,7 +246,22 @@
     }
     if (success == -1)
         PLOG(ERROR) << "Deleting path " << path << " failed";
+    access_ok(path);
     return success == 0;
 }
 
+int renameTo(const char *oldPath, const char *newPath) {
+    int ret = rename(oldPath, newPath);
+    access_ok(oldPath);
+    access_ok(newPath);
+    return ret;
+}
+
+// Calls access(2) on the path to update underlying filesystems,
+// then closes the fd.
+void closeObjFd(int fd, const char *path) {
+    close(fd);
+    access_ok(path);
+}
+
 }  // namespace android
diff --git a/media/mtp/MtpUtils.h b/media/mtp/MtpUtils.h
index 744546b..21f5df0 100644
--- a/media/mtp/MtpUtils.h
+++ b/media/mtp/MtpUtils.h
@@ -34,7 +34,9 @@
 int copyRecursive(const char *fromPath, const char *toPath);
 int copyFile(const char *fromPath, const char *toPath);
 bool deletePath(const char* path);
+int renameTo(const char *oldPath, const char *newPath);
 
+void closeObjFd(int fd, const char *path);
 }; // namespace android
 
 #endif // _MTP_UTILS_H
diff --git a/media/mtp/tests/MtpFfsHandle_test.cpp b/media/mtp/tests/MtpFfsHandle_test.cpp
index d11fe07..c9c9e62 100644
--- a/media/mtp/tests/MtpFfsHandle_test.cpp
+++ b/media/mtp/tests/MtpFfsHandle_test.cpp
@@ -123,6 +123,21 @@
     EXPECT_STREQ(buf, dummyDataStr.c_str());
 }
 
+TYPED_TEST(MtpFfsHandleTest, testReadLarge) {
+    std::stringstream ss;
+    int size = TEST_PACKET_SIZE * MED_MULT;
+    char buf[size + 1];
+    buf[size] = '\0';
+
+    for (int i = 0; i < MED_MULT; i++)
+        ss << dummyDataStr;
+
+    EXPECT_EQ(write(this->bulk_out, ss.str().c_str(), size), size);
+    EXPECT_EQ(this->handle->read(buf, size), size);
+
+    EXPECT_STREQ(buf, ss.str().c_str());
+}
+
 TYPED_TEST(MtpFfsHandleTest, testWrite) {
     char buf[TEST_PACKET_SIZE + 1];
     buf[TEST_PACKET_SIZE] = '\0';
@@ -131,6 +146,21 @@
     EXPECT_STREQ(buf, dummyDataStr.c_str());
 }
 
+TYPED_TEST(MtpFfsHandleTest, testWriteLarge) {
+    std::stringstream ss;
+    int size = TEST_PACKET_SIZE * MED_MULT;
+    char buf[size + 1];
+    buf[size] = '\0';
+
+    for (int i = 0; i < MED_MULT; i++)
+        ss << dummyDataStr;
+
+    EXPECT_EQ(this->handle->write(ss.str().c_str(), size), size);
+    EXPECT_EQ(read(this->bulk_in, buf, size), size);
+
+    EXPECT_STREQ(buf, ss.str().c_str());
+}
+
 TYPED_TEST(MtpFfsHandleTest, testReceiveFileEmpty) {
     std::stringstream ss;
     mtp_file_range mfr;
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 76b29c9..bdd39c6 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1690,6 +1690,7 @@
         recordTrack.clear();
         AudioSystem::releaseInput(portId);
         output.inputId = AUDIO_IO_HANDLE_NONE;
+        output.selectedDeviceId = input.selectedDeviceId;
         portId = AUDIO_PORT_HANDLE_NONE;
     }
     lStatus = AudioSystem::getInputForAttr(&input.attr, &output.inputId,
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index dcf223c..2047dfd 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -595,7 +595,8 @@
             (mConfig.inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO
                     || mConfig.outputCfg.channels != AUDIO_CHANNEL_OUT_STEREO)) {
         // Older effects may require exact STEREO position mask.
-        if (mConfig.inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO) {
+        if (mConfig.inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO
+                && (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_AUXILIARY) {
             ALOGV("Overriding effect input channels %#x as STEREO", mConfig.inputCfg.channels);
             mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
         }
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 923c091..4812b1f 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -245,6 +245,12 @@
     virtual float    getStreamVolumeDB(
                 audio_stream_type_t stream, int index, audio_devices_t device) = 0;
 
+    virtual status_t getSurroundFormats(unsigned int *numSurroundFormats,
+                                        audio_format_t *surroundFormats,
+                                        bool *surroundFormatsEnabled,
+                                        bool reported) = 0;
+    virtual status_t setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled) = 0;
+
     virtual void     setRecordSilenced(uid_t uid, bool silenced);
 };
 
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index 83aec3b..23c020d 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -148,7 +148,8 @@
     case AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND:
         if (config != AUDIO_POLICY_FORCE_NONE &&
                 config != AUDIO_POLICY_FORCE_ENCODED_SURROUND_NEVER &&
-                config != AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS) {
+                config != AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS &&
+                config != AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL) {
             ALOGW("setForceUse() invalid config %d for ENCODED_SURROUND", config);
             return BAD_VALUE;
         }
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index d1d7530..1e5f9ae 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -60,6 +60,26 @@
 // media / notification / system volume.
 constexpr float IN_CALL_EARPIECE_HEADROOM_DB = 3.f;
 
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+// Array of all surround formats.
+static const audio_format_t SURROUND_FORMATS[] = {
+    AUDIO_FORMAT_AC3,
+    AUDIO_FORMAT_E_AC3,
+    AUDIO_FORMAT_DTS,
+    AUDIO_FORMAT_DTS_HD,
+    AUDIO_FORMAT_AAC_LC,
+    AUDIO_FORMAT_DOLBY_TRUEHD,
+    AUDIO_FORMAT_E_AC3_JOC,
+};
+// Array of all AAC formats. When AAC is enabled by users, all AAC formats should be enabled.
+static const audio_format_t AAC_FORMATS[] = {
+    AUDIO_FORMAT_AAC_LC,
+    AUDIO_FORMAT_AAC_HE_V1,
+    AUDIO_FORMAT_AAC_HE_V2,
+    AUDIO_FORMAT_AAC_ELD,
+    AUDIO_FORMAT_AAC_XHE,
+};
+
 // ----------------------------------------------------------------------------
 // AudioPolicyInterface implementation
 // ----------------------------------------------------------------------------
@@ -348,6 +368,9 @@
                                                       const char *device_name)
 {
     status_t status;
+    String8 reply;
+    AudioParameter param;
+    int isReconfigA2dpSupported = 0;
 
     ALOGV("handleDeviceConfigChange(() device: 0x%X, address %s name %s",
           device, device_address, device_name);
@@ -364,6 +387,26 @@
         return NO_ERROR;
     }
 
+    // For offloaded A2DP, Hw modules may have the capability to
+    // configure codecs. Check if any of the loaded hw modules
+    // supports this.
+    // If supported, send a set parameter to configure A2DP codecs
+    // and return. No need to toggle device state.
+    if (device & AUDIO_DEVICE_OUT_ALL_A2DP) {
+        reply = mpClientInterface->getParameters(
+                    AUDIO_IO_HANDLE_NONE,
+                    String8(AudioParameter::keyReconfigA2dpSupported));
+        AudioParameter repliedParameters(reply);
+        repliedParameters.getInt(
+                String8(AudioParameter::keyReconfigA2dpSupported), isReconfigA2dpSupported);
+        if (isReconfigA2dpSupported) {
+            const String8 key(AudioParameter::keyReconfigA2dp);
+            param.add(key, String8("true"));
+            mpClientInterface->setParameters(AUDIO_IO_HANDLE_NONE, param.toString());
+            return NO_ERROR;
+        }
+    }
+
     // Toggle the device state: UNAVAILABLE -> AVAILABLE
     // This will force reading again the device configuration
     status = setDeviceConnectionState(device,
@@ -2768,9 +2811,32 @@
     return NO_ERROR;
 }
 
-status_t AudioPolicyManager::getAudioPort(struct audio_port *port __unused)
+status_t AudioPolicyManager::getAudioPort(struct audio_port *port)
 {
-    return NO_ERROR;
+    if (port == nullptr || port->id == AUDIO_PORT_HANDLE_NONE) {
+        return BAD_VALUE;
+    }
+    sp<DeviceDescriptor> dev = mAvailableOutputDevices.getDeviceFromId(port->id);
+    if (dev != 0) {
+        dev->toAudioPort(port);
+        return NO_ERROR;
+    }
+    dev = mAvailableInputDevices.getDeviceFromId(port->id);
+    if (dev != 0) {
+        dev->toAudioPort(port);
+        return NO_ERROR;
+    }
+    sp<SwAudioOutputDescriptor> out = mOutputs.getOutputFromId(port->id);
+    if (out != 0) {
+        out->toAudioPort(port);
+        return NO_ERROR;
+    }
+    sp<AudioInputDescriptor> in = mInputs.getInputFromId(port->id);
+    if (in != 0) {
+        in->toAudioPort(port);
+        return NO_ERROR;
+    }
+    return BAD_VALUE;
 }
 
 status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch,
@@ -3461,6 +3527,275 @@
     return computeVolume(stream, index, device);
 }
 
+status_t AudioPolicyManager::getSupportedFormats(audio_io_handle_t ioHandle,
+                                                 FormatVector& formats) {
+    if (ioHandle == AUDIO_IO_HANDLE_NONE) {
+        return BAD_VALUE;
+    }
+    String8 reply;
+    reply = mpClientInterface->getParameters(
+            ioHandle, String8(AudioParameter::keyStreamSupportedFormats));
+    ALOGV("%s: supported formats %s", __FUNCTION__, reply.string());
+    AudioParameter repliedParameters(reply);
+    if (repliedParameters.get(
+            String8(AudioParameter::keyStreamSupportedFormats), reply) != NO_ERROR) {
+        ALOGE("%s: failed to retrieve format, bailing out", __FUNCTION__);
+        return BAD_VALUE;
+    }
+    for (auto format : formatsFromString(reply.string())) {
+        // Only AUDIO_FORMAT_AAC_LC will be used in Settings UI for all AAC formats.
+        for (size_t i = 0; i < ARRAY_SIZE(AAC_FORMATS); i++) {
+            if (format == AAC_FORMATS[i]) {
+                format = AUDIO_FORMAT_AAC_LC;
+                break;
+            }
+        }
+        bool exist = false;
+        for (size_t i = 0; i < formats.size(); i++) {
+            if (format == formats[i]) {
+                exist = true;
+                break;
+            }
+        }
+        bool isSurroundFormat = false;
+        for (size_t i = 0; i < ARRAY_SIZE(SURROUND_FORMATS); i++) {
+            if (SURROUND_FORMATS[i] == format) {
+                isSurroundFormat = true;
+                break;
+            }
+        }
+        if (!exist && isSurroundFormat) {
+            formats.add(format);
+        }
+    }
+    return NO_ERROR;
+}
+
+status_t AudioPolicyManager::getSurroundFormats(unsigned int *numSurroundFormats,
+                                                audio_format_t *surroundFormats,
+                                                bool *surroundFormatsEnabled,
+                                                bool reported)
+{
+    if (numSurroundFormats == NULL || (*numSurroundFormats != 0 &&
+            (surroundFormats == NULL || surroundFormatsEnabled == NULL))) {
+        return BAD_VALUE;
+    }
+    ALOGV("getSurroundFormats() numSurroundFormats %d surroundFormats %p surroundFormatsEnabled %p",
+            *numSurroundFormats, surroundFormats, surroundFormatsEnabled);
+
+    // Only return value if there is HDMI output.
+    if ((mAvailableOutputDevices.types() & AUDIO_DEVICE_OUT_HDMI) == 0) {
+        return INVALID_OPERATION;
+    }
+
+    size_t formatsWritten = 0;
+    size_t formatsMax = *numSurroundFormats;
+    *numSurroundFormats = 0;
+    FormatVector formats;
+    if (reported) {
+        // Only get surround formats which are reported by device.
+        // First list already open outputs that can be routed to this device
+        audio_devices_t device = AUDIO_DEVICE_OUT_HDMI;
+        SortedVector<audio_io_handle_t> outputs;
+        bool reportedFormatFound = false;
+        status_t status;
+        sp<SwAudioOutputDescriptor> desc;
+        for (size_t i = 0; i < mOutputs.size(); i++) {
+            desc = mOutputs.valueAt(i);
+            if (!desc->isDuplicated() && (desc->supportedDevices() & device)) {
+                outputs.add(mOutputs.keyAt(i));
+            }
+        }
+        // Open an output to query dynamic parameters.
+        DeviceVector hdmiOutputDevices = mAvailableOutputDevices.getDevicesFromType(
+                AUDIO_DEVICE_OUT_HDMI);
+        for (size_t i = 0; i < hdmiOutputDevices.size(); i++) {
+            String8 address = hdmiOutputDevices[i]->mAddress;
+            for (const auto& hwModule : mHwModules) {
+                for (size_t i = 0; i < hwModule->getOutputProfiles().size(); i++) {
+                    sp<IOProfile> profile = hwModule->getOutputProfiles()[i];
+                    if (profile->supportDevice(AUDIO_DEVICE_OUT_HDMI) &&
+                            profile->supportDeviceAddress(address)) {
+                        size_t j;
+                        for (j = 0; j < outputs.size(); j++) {
+                            desc = mOutputs.valueFor(outputs.itemAt(j));
+                            if (!desc->isDuplicated() && desc->mProfile == profile) {
+                                break;
+                            }
+                        }
+                        if (j != outputs.size()) {
+                            status = getSupportedFormats(outputs.itemAt(j), formats);
+                            reportedFormatFound |= (status == NO_ERROR);
+                            continue;
+                        }
+
+                        if (!profile->canOpenNewIo()) {
+                            ALOGW("Max Output number %u already opened for this profile %s",
+                                  profile->maxOpenCount, profile->getTagName().c_str());
+                            continue;
+                        }
+
+                        ALOGV("opening output for device %08x with params %s profile %p name %s",
+                              device, address.string(), profile.get(), profile->getName().string());
+                        desc = new SwAudioOutputDescriptor(profile, mpClientInterface);
+                        audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
+                        status_t status = desc->open(nullptr, device, address,
+                                                     AUDIO_STREAM_DEFAULT, AUDIO_OUTPUT_FLAG_NONE,
+                                                     &output);
+
+                        if (status == NO_ERROR) {
+                            status = getSupportedFormats(output, formats);
+                            reportedFormatFound |= (status == NO_ERROR);
+                            desc->close();
+                            output = AUDIO_IO_HANDLE_NONE;
+                        }
+                    }
+                }
+            }
+        }
+
+        if (!reportedFormatFound) {
+            return UNKNOWN_ERROR;
+        }
+    } else {
+        for (size_t i = 0; i < ARRAY_SIZE(SURROUND_FORMATS); i++) {
+            formats.add(SURROUND_FORMATS[i]);
+        }
+    }
+    for (size_t i = 0; i < formats.size(); i++) {
+        if (formatsWritten < formatsMax) {
+            surroundFormats[formatsWritten] = formats[i];
+            bool formatEnabled = false;
+            if (formats[i] == AUDIO_FORMAT_AAC_LC) {
+                for (size_t j = 0; j < ARRAY_SIZE(AAC_FORMATS); j++) {
+                    formatEnabled =
+                            mSurroundFormats.find(AAC_FORMATS[i]) != mSurroundFormats.end();
+                    break;
+                }
+            } else {
+                formatEnabled = mSurroundFormats.find(formats[i]) != mSurroundFormats.end();
+            }
+            surroundFormatsEnabled[formatsWritten++] = formatEnabled;
+        }
+        (*numSurroundFormats)++;
+    }
+    return NO_ERROR;
+}
+
+status_t AudioPolicyManager::setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled)
+{
+    // Check if audio format is a surround formats.
+    bool isSurroundFormat = false;
+    for (size_t i = 0; i < ARRAY_SIZE(SURROUND_FORMATS); i++) {
+        if (audioFormat == SURROUND_FORMATS[i]) {
+            isSurroundFormat = true;
+            break;
+        }
+    }
+    if (!isSurroundFormat) {
+        return BAD_VALUE;
+    }
+
+    // Should only be called when MANUAL.
+    audio_policy_forced_cfg_t forceUse = mEngine->getForceUse(
+                AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND);
+    if (forceUse != AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL) {
+        return INVALID_OPERATION;
+    }
+
+    if ((mSurroundFormats.find(audioFormat) != mSurroundFormats.end() && enabled)
+            || (mSurroundFormats.find(audioFormat) == mSurroundFormats.end() && !enabled)) {
+        return NO_ERROR;
+    }
+
+    // The operation is valid only when there is HDMI output available.
+    if ((mAvailableOutputDevices.types() & AUDIO_DEVICE_OUT_HDMI) == 0) {
+        return INVALID_OPERATION;
+    }
+
+    if (enabled) {
+        if (audioFormat == AUDIO_FORMAT_AAC_LC) {
+            for (size_t i = 0; i < ARRAY_SIZE(AAC_FORMATS); i++) {
+                mSurroundFormats.insert(AAC_FORMATS[i]);
+            }
+        } else {
+            mSurroundFormats.insert(audioFormat);
+        }
+    } else {
+        if (audioFormat == AUDIO_FORMAT_AAC_LC) {
+            for (size_t i = 0; i < ARRAY_SIZE(AAC_FORMATS); i++) {
+                mSurroundFormats.erase(AAC_FORMATS[i]);
+            }
+        } else {
+            mSurroundFormats.erase(audioFormat);
+        }
+    }
+
+    sp<SwAudioOutputDescriptor> outputDesc;
+    bool profileUpdated = false;
+    DeviceVector hdmiOutputDevices = mAvailableOutputDevices.getDevicesFromType(
+            AUDIO_DEVICE_OUT_HDMI);
+    for (size_t i = 0; i < hdmiOutputDevices.size(); i++) {
+        // Simulate reconnection to update enabled surround sound formats.
+        String8 address = hdmiOutputDevices[i]->mAddress;
+        String8 name = hdmiOutputDevices[i]->getName();
+        status_t status = setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_HDMI,
+                                                      AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+                                                      address.c_str(),
+                                                      name.c_str());
+        if (status != NO_ERROR) {
+            continue;
+        }
+        status = setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_HDMI,
+                                             AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+                                             address.c_str(),
+                                             name.c_str());
+        profileUpdated |= (status == NO_ERROR);
+    }
+    DeviceVector hdmiInputDevices = mAvailableInputDevices.getDevicesFromType(
+                AUDIO_DEVICE_IN_HDMI);
+    for (size_t i = 0; i < hdmiInputDevices.size(); i++) {
+        // Simulate reconnection to update enabled surround sound formats.
+        String8 address = hdmiInputDevices[i]->mAddress;
+        String8 name = hdmiInputDevices[i]->getName();
+        status_t status = setDeviceConnectionStateInt(AUDIO_DEVICE_IN_HDMI,
+                                                      AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+                                                      address.c_str(),
+                                                      name.c_str());
+        if (status != NO_ERROR) {
+            continue;
+        }
+        status = setDeviceConnectionStateInt(AUDIO_DEVICE_IN_HDMI,
+                                             AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+                                             address.c_str(),
+                                             name.c_str());
+        profileUpdated |= (status == NO_ERROR);
+    }
+
+    // Undo the surround formats change due to no audio profiles updated.
+    if (!profileUpdated) {
+        if (enabled) {
+            if (audioFormat == AUDIO_FORMAT_AAC_LC) {
+                for (size_t i = 0; i < ARRAY_SIZE(AAC_FORMATS); i++) {
+                    mSurroundFormats.erase(AAC_FORMATS[i]);
+                }
+            } else {
+                mSurroundFormats.erase(audioFormat);
+            }
+        } else {
+            if (audioFormat == AUDIO_FORMAT_AAC_LC) {
+                for (size_t i = 0; i < ARRAY_SIZE(AAC_FORMATS); i++) {
+                    mSurroundFormats.insert(AAC_FORMATS[i]);
+                }
+            } else {
+                mSurroundFormats.insert(audioFormat);
+            }
+        }
+    }
+
+    return profileUpdated ? NO_ERROR : INVALID_OPERATION;
+}
+
 void AudioPolicyManager::setRecordSilenced(uid_t uid, bool silenced)
 {
     ALOGV("AudioPolicyManager:setRecordSilenced(uid:%d, silenced:%d)", uid, silenced);
@@ -3834,6 +4169,7 @@
    mInputs.clear();
    mHwModules.clear();
    mHwModulesAll.clear();
+   mSurroundFormats.clear();
 }
 
 status_t AudioPolicyManager::initCheck()
@@ -4382,14 +4718,23 @@
     }
 
     if (!vectorsEqual(srcOutputs,dstOutputs)) {
+        // get maximum latency of all source outputs to determine the minimum mute time guaranteeing
+        // audio from invalidated tracks will be rendered when unmuting
+        uint32_t maxLatency = 0;
+        for (audio_io_handle_t srcOut : srcOutputs) {
+            sp<SwAudioOutputDescriptor> desc = mPreviousOutputs.valueFor(srcOut);
+            if (desc != 0 && maxLatency < desc->latency()) {
+                maxLatency = desc->latency();
+            }
+        }
         ALOGV("checkOutputForStrategy() strategy %d, moving from output %d to output %d",
               strategy, srcOutputs[0], dstOutputs[0]);
         // mute strategy while moving tracks from one output to another
         for (audio_io_handle_t srcOut : srcOutputs) {
-            sp<SwAudioOutputDescriptor> desc = mOutputs.valueFor(srcOut);
-            if (isStrategyActive(desc, strategy)) {
+            sp<SwAudioOutputDescriptor> desc = mPreviousOutputs.valueFor(srcOut);
+            if (desc != 0 && isStrategyActive(desc, strategy)) {
                 setStrategyMute(strategy, true, desc);
-                setStrategyMute(strategy, false, desc, MUTE_TIME_MS, newDevice);
+                setStrategyMute(strategy, false, desc, maxLatency * LATENCY_MUTE_FACTOR, newDevice);
             }
             sp<AudioSourceDescriptor> source =
                     getSourceForStrategyOnOutput(srcOut, strategy);
@@ -5581,81 +5926,110 @@
             AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND);
     ALOGD("%s: forced use = %d", __FUNCTION__, forceUse);
 
-    // Analyze original support for various formats.
-    bool supportsAC3 = false;
-    bool supportsOtherSurround = false;
-    bool supportsIEC61937 = false;
-    for (ssize_t formatIndex = 0; formatIndex < (ssize_t)formats.size(); formatIndex++) {
-        audio_format_t format = formats[formatIndex];
-        switch (format) {
-            case AUDIO_FORMAT_AC3:
-                supportsAC3 = true;
-                break;
-            case AUDIO_FORMAT_E_AC3:
-            case AUDIO_FORMAT_DTS:
-            case AUDIO_FORMAT_DTS_HD:
-                // If ALWAYS, remove all other surround formats here since we will add them later.
-                if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS) {
-                    formats.removeAt(formatIndex);
-                    formatIndex--;
-                }
-                supportsOtherSurround = true;
-                break;
-            case AUDIO_FORMAT_IEC61937:
-                supportsIEC61937 = true;
-                break;
-            default:
-                break;
+    // If MANUAL, keep the supported surround sound formats as current enabled ones.
+    if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL) {
+        formats.clear();
+        for (auto it = mSurroundFormats.begin(); it != mSurroundFormats.end(); it++) {
+            formats.add(*it);
         }
-    }
+        // Always enable IEC61937 when in MANUAL mode.
+        formats.add(AUDIO_FORMAT_IEC61937);
+    } else { // NEVER, AUTO or ALWAYS
+        // Analyze original support for various formats.
+        bool supportsAC3 = false;
+        bool supportsOtherSurround = false;
+        bool supportsIEC61937 = false;
+        mSurroundFormats.clear();
+        for (ssize_t formatIndex = 0; formatIndex < (ssize_t)formats.size(); formatIndex++) {
+            audio_format_t format = formats[formatIndex];
+            switch (format) {
+                case AUDIO_FORMAT_AC3:
+                    supportsAC3 = true;
+                    break;
+                case AUDIO_FORMAT_E_AC3:
+                case AUDIO_FORMAT_DTS:
+                case AUDIO_FORMAT_DTS_HD:
+                    // If ALWAYS, remove all other surround formats here
+                    // since we will add them later.
+                    if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS) {
+                        formats.removeAt(formatIndex);
+                        formatIndex--;
+                    }
+                    supportsOtherSurround = true;
+                    break;
+                case AUDIO_FORMAT_IEC61937:
+                    supportsIEC61937 = true;
+                    break;
+                default:
+                    break;
+            }
+        }
 
-    // Modify formats based on surround preferences.
-    // If NEVER, remove support for surround formats.
-    if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_NEVER) {
-        if (supportsAC3 || supportsOtherSurround || supportsIEC61937) {
-            // Remove surround sound related formats.
-            for (size_t formatIndex = 0; formatIndex < formats.size(); ) {
+        // Modify formats based on surround preferences.
+        // If NEVER, remove support for surround formats.
+        if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_NEVER) {
+            if (supportsAC3 || supportsOtherSurround || supportsIEC61937) {
+                // Remove surround sound related formats.
+                for (size_t formatIndex = 0; formatIndex < formats.size(); ) {
+                    audio_format_t format = formats[formatIndex];
+                    switch(format) {
+                        case AUDIO_FORMAT_AC3:
+                        case AUDIO_FORMAT_E_AC3:
+                        case AUDIO_FORMAT_DTS:
+                        case AUDIO_FORMAT_DTS_HD:
+                        case AUDIO_FORMAT_IEC61937:
+                            formats.removeAt(formatIndex);
+                            break;
+                        default:
+                            formatIndex++; // keep it
+                            break;
+                    }
+                }
+                supportsAC3 = false;
+                supportsOtherSurround = false;
+                supportsIEC61937 = false;
+            }
+        } else { // AUTO or ALWAYS
+            // Most TVs support AC3 even if they do not report it in the EDID.
+            if ((alwaysForceAC3 || (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS))
+                    && !supportsAC3) {
+                formats.add(AUDIO_FORMAT_AC3);
+                supportsAC3 = true;
+            }
+
+            // If ALWAYS, add support for raw surround formats if all are missing.
+            // This assumes that if any of these formats are reported by the HAL
+            // then the report is valid and should not be modified.
+            if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS) {
+                formats.add(AUDIO_FORMAT_E_AC3);
+                formats.add(AUDIO_FORMAT_DTS);
+                formats.add(AUDIO_FORMAT_DTS_HD);
+                supportsOtherSurround = true;
+            }
+
+            // Add support for IEC61937 if any raw surround supported.
+            // The HAL could do this but add it here, just in case.
+            if ((supportsAC3 || supportsOtherSurround) && !supportsIEC61937) {
+                formats.add(AUDIO_FORMAT_IEC61937);
+                supportsIEC61937 = true;
+            }
+
+            // Add reported surround sound formats to enabled surround formats.
+            for (size_t formatIndex = 0; formatIndex < formats.size(); formatIndex++) {
                 audio_format_t format = formats[formatIndex];
                 switch(format) {
                     case AUDIO_FORMAT_AC3:
                     case AUDIO_FORMAT_E_AC3:
                     case AUDIO_FORMAT_DTS:
                     case AUDIO_FORMAT_DTS_HD:
-                    case AUDIO_FORMAT_IEC61937:
-                        formats.removeAt(formatIndex);
-                        break;
+                    case AUDIO_FORMAT_AAC_LC:
+                    case AUDIO_FORMAT_DOLBY_TRUEHD:
+                    case AUDIO_FORMAT_E_AC3_JOC:
+                        mSurroundFormats.insert(format);
                     default:
-                        formatIndex++; // keep it
                         break;
                 }
             }
-            supportsAC3 = false;
-            supportsOtherSurround = false;
-            supportsIEC61937 = false;
-        }
-    } else { // AUTO or ALWAYS
-        // Most TVs support AC3 even if they do not report it in the EDID.
-        if ((alwaysForceAC3 || (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS))
-                && !supportsAC3) {
-            formats.add(AUDIO_FORMAT_AC3);
-            supportsAC3 = true;
-        }
-
-        // If ALWAYS, add support for raw surround formats if all are missing.
-        // This assumes that if any of these formats are reported by the HAL
-        // then the report is valid and should not be modified.
-        if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS) {
-            formats.add(AUDIO_FORMAT_E_AC3);
-            formats.add(AUDIO_FORMAT_DTS);
-            formats.add(AUDIO_FORMAT_DTS_HD);
-            supportsOtherSurround = true;
-        }
-
-        // Add support for IEC61937 if any raw surround supported.
-        // The HAL could do this but add it here, just in case.
-        if ((supportsAC3 || supportsOtherSurround) && !supportsIEC61937) {
-            formats.add(AUDIO_FORMAT_IEC61937);
-            supportsIEC61937 = true;
         }
     }
 }
@@ -5677,8 +6051,9 @@
                 maskIndex++;
             }
         }
-    // If ALWAYS, then make sure we at least support 5.1
-    } else if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS) {
+    // If ALWAYS or MANUAL, then make sure we at least support 5.1
+    } else if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS
+            || forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL) {
         bool supports5dot1 = false;
         // Are there any channel masks that can be considered "surround"?
         for (audio_channel_mask_t channelMask : channelMasks) {
@@ -5705,7 +6080,7 @@
     if (profiles.hasDynamicFormat()) {
         reply = mpClientInterface->getParameters(
                 ioHandle, String8(AudioParameter::keyStreamSupportedFormats));
-        ALOGV("%s: supported formats %s", __FUNCTION__, reply.string());
+        ALOGV("%s: supported formats %d, %s", __FUNCTION__, ioHandle, reply.string());
         AudioParameter repliedParameters(reply);
         if (repliedParameters.get(
                 String8(AudioParameter::keyStreamSupportedFormats), reply) != NO_ERROR) {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 2b68882..b954714 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -18,6 +18,7 @@
 
 #include <atomic>
 #include <memory>
+#include <unordered_set>
 
 #include <stdint.h>
 #include <sys/types.h>
@@ -67,6 +68,10 @@
 // is switched
 #define MUTE_TIME_MS 2000
 
+// multiplication factor applied to output latency when calculating a safe mute delay when
+// invalidating tracks
+#define LATENCY_MUTE_FACTOR 4
+
 #define NUM_TEST_OUTPUTS 5
 
 #define NUM_VOL_CURVE_KNEES 2
@@ -233,6 +238,12 @@
         virtual float    getStreamVolumeDB(
                     audio_stream_type_t stream, int index, audio_devices_t device);
 
+        virtual status_t getSurroundFormats(unsigned int *numSurroundFormats,
+                                            audio_format_t *surroundFormats,
+                                            bool *surroundFormatsEnabled,
+                                            bool reported);
+        virtual status_t setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled);
+
         // return the strategy corresponding to a given stream type
         routing_strategy getStrategy(audio_stream_type_t stream) const;
 
@@ -592,11 +603,16 @@
 
         // Audio Policy Engine Interface.
         AudioPolicyManagerInterface *mEngine;
+
+        // Surround formats that are enabled.
+        std::unordered_set<audio_format_t> mSurroundFormats;
 private:
         // Add or remove AC3 DTS encodings based on user preferences.
         void filterSurroundFormats(FormatVector *formatsPtr);
         void filterSurroundChannelMasks(ChannelsVector *channelMasksPtr);
 
+        status_t getSupportedFormats(audio_io_handle_t ioHandle, FormatVector& formats);
+
         // If any, resolve any "dynamic" fields of an Audio Profiles collection
         void updateAudioProfiles(audio_devices_t device, audio_io_handle_t ioHandle,
                 AudioProfileVector &profiles);
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index f6d407f..66ac050 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -408,6 +408,7 @@
         client->active = false;
         client->isConcurrent = false;
         client->isVirtualDevice = false; //TODO : update from APM->getInputForAttr()
+        client->deviceId = *selectedDeviceId;
         mAudioRecordClients.add(*portId, client);
     }
 
@@ -434,7 +435,8 @@
     return rawbuffer;
 }
 
-static std::string audioConcurrencyString(AudioPolicyInterface::concurrency_type__mask_t concurrency)
+static std::string audioConcurrencyString(
+        AudioPolicyInterface::concurrency_type__mask_t concurrency)
 {
     char buffer[64]; // oversized
     if (concurrency & AudioPolicyInterface::API_INPUT_CONCURRENCY_ALL) {
@@ -450,6 +452,17 @@
     return &buffer[1];
 }
 
+std::string AudioPolicyService::getDeviceTypeStrForPortId(audio_port_handle_t portId) {
+    std::string typeStr;
+    struct audio_port port = {};
+    port.id = portId;
+    status_t status = mAudioPolicyManager->getAudioPort(&port);
+    if (status == NO_ERROR && port.type == AUDIO_PORT_TYPE_DEVICE) {
+        deviceToString(port.ext.device.type, typeStr);
+    }
+    return typeStr;
+}
+
 status_t AudioPolicyService::startInput(audio_port_handle_t portId, bool *silenced)
 {
     if (mAudioPolicyManager == NULL) {
@@ -498,9 +511,14 @@
         static constexpr char kAudioPolicyRqstSrc[] = "android.media.audiopolicy.rqst.src";
         static constexpr char kAudioPolicyRqstPkg[] = "android.media.audiopolicy.rqst.pkg";
         static constexpr char kAudioPolicyRqstSession[] = "android.media.audiopolicy.rqst.session";
+        static constexpr char kAudioPolicyRqstDevice[] =
+                "android.media.audiopolicy.rqst.device";
         static constexpr char kAudioPolicyActiveSrc[] = "android.media.audiopolicy.active.src";
         static constexpr char kAudioPolicyActivePkg[] = "android.media.audiopolicy.active.pkg";
-        static constexpr char kAudioPolicyActiveSession[] = "android.media.audiopolicy.active.session";
+        static constexpr char kAudioPolicyActiveSession[] =
+                "android.media.audiopolicy.active.session";
+        static constexpr char kAudioPolicyActiveDevice[] =
+                "android.media.audiopolicy.active.device";
 
         MediaAnalyticsItem *item = new MediaAnalyticsItem(kAudioPolicy);
         if (item != NULL) {
@@ -508,10 +526,15 @@
             item->setCString(kAudioPolicyReason, audioConcurrencyString(concurrency).c_str());
             item->setInt32(kAudioPolicyStatus, status);
 
-            item->setCString(kAudioPolicyRqstSrc, audioSourceString(client->attributes.source).c_str());
-            item->setCString(kAudioPolicyRqstPkg, std::string(String8(client->opPackageName).string()).c_str());
+            item->setCString(kAudioPolicyRqstSrc,
+                             audioSourceString(client->attributes.source).c_str());
+            item->setCString(kAudioPolicyRqstPkg,
+                             std::string(String8(client->opPackageName).string()).c_str());
             item->setInt32(kAudioPolicyRqstSession, client->session);
 
+            item->setCString(
+                    kAudioPolicyRqstDevice, getDeviceTypeStrForPortId(client->deviceId).c_str());
+
             // figure out who is active
             // NB: might the other party have given up the microphone since then? how sure.
             // perhaps could have given up on it.
@@ -527,8 +550,11 @@
                         // keeps the last of the clients marked active
                         item->setCString(kAudioPolicyActiveSrc,
                                          audioSourceString(other->attributes.source).c_str());
-                        item->setCString(kAudioPolicyActivePkg, std::string(String8(other->opPackageName).string()).c_str());
+                        item->setCString(kAudioPolicyActivePkg,
+                                     std::string(String8(other->opPackageName).string()).c_str());
                         item->setInt32(kAudioPolicyActiveSession, other->session);
+                        item->setCString(kAudioPolicyActiveDevice,
+                                         getDeviceTypeStrForPortId(other->deviceId).c_str());
                     }
                 }
             }
@@ -986,5 +1012,28 @@
     return mAudioPolicyManager->getStreamVolumeDB(stream, index, device);
 }
 
+status_t AudioPolicyService::getSurroundFormats(unsigned int *numSurroundFormats,
+                                                audio_format_t *surroundFormats,
+                                                bool *surroundFormatsEnabled,
+                                                bool reported)
+{
+    if (mAudioPolicyManager == NULL) {
+        return NO_INIT;
+    }
+    Mutex::Autolock _l(mLock);
+    AutoCallerClear acc;
+    return mAudioPolicyManager->getSurroundFormats(numSurroundFormats, surroundFormats,
+                                                   surroundFormatsEnabled, reported);
+}
+
+status_t AudioPolicyService::setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled)
+{
+    if (mAudioPolicyManager == NULL) {
+        return NO_INIT;
+    }
+    Mutex::Autolock _l(mLock);
+    AutoCallerClear acc;
+    return mAudioPolicyManager->setSurroundFormatEnabled(audioFormat, enabled);
+}
 
 } // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index d8dd797..407d7a5 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -203,6 +203,12 @@
     virtual float    getStreamVolumeDB(
                 audio_stream_type_t stream, int index, audio_devices_t device);
 
+    virtual status_t getSurroundFormats(unsigned int *numSurroundFormats,
+                                        audio_format_t *surroundFormats,
+                                        bool *surroundFormatsEnabled,
+                                        bool reported);
+    virtual status_t setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled);
+
             status_t doStopOutput(audio_io_handle_t output,
                                   audio_stream_type_t stream,
                                   audio_session_t session);
@@ -257,6 +263,8 @@
     // Prints the shell command help
     status_t printHelp(int out);
 
+    std::string getDeviceTypeStrForPortId(audio_port_handle_t portId);
+
     // If recording we need to make sure the UID is allowed to do that. If the UID is idle
     // then it cannot record and gets buffers with zeros - silence. As soon as the UID
     // transitions to an active state we will start reporting buffers with data. This approach
@@ -637,7 +645,8 @@
         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()
+        bool isVirtualDevice;          // uses virtual device: updated by APM::getInputForAttr()
+        audio_port_handle_t deviceId;  // selected input device port ID
     };
 
     // A class automatically clearing and restoring binder caller identity inside
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 6b958a8..9acbf0a 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -4045,6 +4045,7 @@
         mRepeatingLastFrameNumber(
             hardware::camera2::ICameraDeviceUser::NO_IN_FLIGHT_REPEATING_FRAMES),
         mPrepareVideoStream(false),
+        mConstrainedMode(false),
         mRequestLatency(kRequestLatencyBinSize),
         mSessionParamKeys(sessionParamKeys),
         mLatestSessionParams(sessionParamKeys.size()) {
@@ -4068,6 +4069,7 @@
     mLatestSessionParams = sessionParams;
     // Prepare video stream for high speed recording.
     mPrepareVideoStream = isConstrainedHighSpeed;
+    mConstrainedMode = isConstrainedHighSpeed;
 }
 
 status_t Camera3Device::RequestThread::queueRequestList(
@@ -4482,6 +4484,17 @@
     return maxExpectedDuration;
 }
 
+bool Camera3Device::RequestThread::skipHFRTargetFPSUpdate(int32_t tag,
+        const camera_metadata_ro_entry_t& newEntry, const camera_metadata_entry_t& currentEntry) {
+    if (mConstrainedMode && (ANDROID_CONTROL_AE_TARGET_FPS_RANGE == tag) &&
+            (newEntry.count == currentEntry.count) && (currentEntry.count == 2) &&
+            (currentEntry.data.i32[1] == newEntry.data.i32[1])) {
+        return true;
+    }
+
+    return false;
+}
+
 bool Camera3Device::RequestThread::updateSessionParameters(const CameraMetadata& settings) {
     ATRACE_CALL();
     bool updatesDetected = false;
@@ -4514,8 +4527,10 @@
 
             if (isDifferent) {
                 ALOGV("%s: Session parameter tag id %d changed", __FUNCTION__, tag);
+                if (!skipHFRTargetFPSUpdate(tag, entry, lastEntry)) {
+                    updatesDetected = true;
+                }
                 mLatestSessionParams.update(entry);
-                updatesDetected = true;
             }
         } else if (lastEntry.count > 0) {
             // Value has been removed
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 13b83ba..5372407 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -861,6 +861,11 @@
         // Check and update latest session parameters based on the current request settings.
         bool updateSessionParameters(const CameraMetadata& settings);
 
+        // Check whether FPS range session parameter re-configuration is needed in constrained
+        // high speed recording camera sessions.
+        bool skipHFRTargetFPSUpdate(int32_t tag, const camera_metadata_ro_entry_t& newEntry,
+                const camera_metadata_entry_t& currentEntry);
+
         // Re-configure camera using the latest session parameters.
         bool reconfigureCamera();
 
@@ -919,6 +924,8 @@
         // Flag indicating if we should prepare video stream for video requests.
         bool               mPrepareVideoStream;
 
+        bool               mConstrainedMode;
+
         static const int32_t kRequestLatencyBinSize = 40; // in ms
         CameraLatencyHistogram mRequestLatency;
 
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index 5675b0b..6a72e5b 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -144,15 +144,14 @@
 // If a close request is pending then close the stream
 bool AAudioService::releaseStream(const sp<AAudioServiceStreamBase> &serviceStream) {
     bool closed = false;
-    if ((serviceStream->decrementServiceReferenceCount() == 0) && serviceStream->isCloseNeeded()) {
-        // removeStreamByHandle() uses a lock so that if there are two simultaneous closes
-        // then only one will get the pointer and do the close.
-        sp<AAudioServiceStreamBase> foundStream = mStreamTracker.removeStreamByHandle(serviceStream->getHandle());
-        if (foundStream.get() != nullptr) {
-            foundStream->close();
-            pid_t pid = foundStream->getOwnerProcessId();
-            AAudioClientTracker::getInstance().unregisterClientStream(pid, foundStream);
-        }
+    // decrementAndRemoveStreamByHandle() uses a lock so that if there are two simultaneous closes
+    // then only one will get the pointer and do the close.
+    sp<AAudioServiceStreamBase> foundStream = mStreamTracker.decrementAndRemoveStreamByHandle(
+            serviceStream->getHandle());
+    if (foundStream.get() != nullptr) {
+        foundStream->close();
+        pid_t pid = foundStream->getOwnerProcessId();
+        AAudioClientTracker::getInstance().unregisterClientStream(pid, foundStream);
         closed = true;
     }
     return closed;
@@ -175,14 +174,15 @@
     pid_t pid = serviceStream->getOwnerProcessId();
     AAudioClientTracker::getInstance().unregisterClientStream(pid, serviceStream);
 
-    serviceStream->setCloseNeeded(true);
+    serviceStream->markCloseNeeded();
     (void) releaseStream(serviceStream);
     return AAUDIO_OK;
 }
 
 sp<AAudioServiceStreamBase> AAudioService::convertHandleToServiceStream(
         aaudio_handle_t streamHandle) {
-    sp<AAudioServiceStreamBase> serviceStream = mStreamTracker.getStreamByHandle(streamHandle);
+    sp<AAudioServiceStreamBase> serviceStream = mStreamTracker.getStreamByHandleAndIncrement(
+            streamHandle);
     if (serviceStream.get() != nullptr) {
         // Only allow owner or the aaudio service to access the stream.
         const uid_t callingUserId = IPCThreadState::self()->getCallingUid();
@@ -194,9 +194,9 @@
         if (!allowed) {
             ALOGE("AAudioService: calling uid %d cannot access stream 0x%08X owned by %d",
                   callingUserId, streamHandle, ownerUserId);
+            // We incremented the reference count so we must check if it needs to be closed.
+            checkForPendingClose(serviceStream, AAUDIO_OK);
             serviceStream.clear();
-        } else {
-            serviceStream->incrementServiceReferenceCount();
         }
     }
     return serviceStream;
@@ -328,12 +328,11 @@
 aaudio_result_t AAudioService::disconnectStreamByPortHandle(audio_port_handle_t portHandle) {
     ALOGD("%s(%d) called", __func__, portHandle);
     sp<AAudioServiceStreamBase> serviceStream =
-            mStreamTracker.findStreamByPortHandle(portHandle);
+            mStreamTracker.findStreamByPortHandleAndIncrement(portHandle);
     if (serviceStream.get() == nullptr) {
         ALOGE("%s(), could not find stream with portHandle = %d", __func__, portHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
-    serviceStream->incrementServiceReferenceCount();
     aaudio_result_t result = serviceStream->stop();
     serviceStream->disconnect();
     return checkForPendingClose(serviceStream, result);
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index 48d8002..9af8af3 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -414,12 +414,13 @@
     sendServiceEvent(AAUDIO_SERVICE_EVENT_VOLUME, volume);
 }
 
-int32_t AAudioServiceStreamBase::incrementServiceReferenceCount() {
-    std::lock_guard<std::mutex> lock(mCallingCountLock);
+int32_t AAudioServiceStreamBase::incrementServiceReferenceCount_l() {
     return ++mCallingCount;
 }
 
-int32_t AAudioServiceStreamBase::decrementServiceReferenceCount() {
-    std::lock_guard<std::mutex> lock(mCallingCountLock);
-    return --mCallingCount;
+int32_t AAudioServiceStreamBase::decrementServiceReferenceCount_l() {
+    int32_t count = --mCallingCount;
+    // Each call to increment should be balanced with one call to decrement.
+    assert(count >= 0);
+    return count;
 }
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index 0ad015e..a1815d0 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -205,22 +205,33 @@
 
     /**
      * Atomically increment the number of active references to the stream by AAudioService.
+     *
+     * This is called under a global lock in AAudioStreamTracker.
+     *
      * @return value after the increment
      */
-    int32_t incrementServiceReferenceCount();
+    int32_t incrementServiceReferenceCount_l();
 
     /**
      * Atomically decrement the number of active references to the stream by AAudioService.
+     * This should only be called after incrementServiceReferenceCount_l().
+     *
+     * This is called under a global lock in AAudioStreamTracker.
+     *
      * @return value after the decrement
      */
-    int32_t decrementServiceReferenceCount();
+    int32_t decrementServiceReferenceCount_l();
 
     bool isCloseNeeded() const {
         return mCloseNeeded.load();
     }
 
-    void setCloseNeeded(bool needed) {
-        mCloseNeeded.store(needed);
+    /**
+     * Mark this stream as needing to be closed.
+     * Once marked for closing, it cannot be unmarked.
+     */
+    void markCloseNeeded() {
+        mCloseNeeded.store(true);
     }
 
     virtual const char *getTypeText() const { return "Base"; }
@@ -290,8 +301,9 @@
     aaudio_handle_t         mHandle = -1;
     bool                    mFlowing = false;
 
-    std::mutex              mCallingCountLock;
-    std::atomic<int32_t>    mCallingCount{0};
+    // This is modified under a global lock in AAudioStreamTracker.
+    int32_t                 mCallingCount = 0;
+
     std::atomic<bool>       mCloseNeeded{false};
 };
 
diff --git a/services/oboeservice/AAudioStreamTracker.cpp b/services/oboeservice/AAudioStreamTracker.cpp
index 9d5d8fc..3328159 100644
--- a/services/oboeservice/AAudioStreamTracker.cpp
+++ b/services/oboeservice/AAudioStreamTracker.cpp
@@ -30,34 +30,40 @@
 using namespace android;
 using namespace aaudio;
 
-sp<AAudioServiceStreamBase> AAudioStreamTracker::removeStreamByHandle(
+sp<AAudioServiceStreamBase> AAudioStreamTracker::decrementAndRemoveStreamByHandle(
+        aaudio_handle_t streamHandle) {
+    std::lock_guard<std::mutex> lock(mHandleLock);
+    sp<AAudioServiceStreamBase> serviceStream;
+    auto it = mStreamsByHandle.find(streamHandle);
+    if (it != mStreamsByHandle.end()) {
+        sp<AAudioServiceStreamBase> tempStream = it->second;
+        // Does the caller need to close the stream?
+        // The reference count should never be negative.
+        // But it is safer to check for <= 0 than == 0.
+        if ((tempStream->decrementServiceReferenceCount_l() <= 0) && tempStream->isCloseNeeded()) {
+            serviceStream = tempStream; // Only return stream if ready to be closed.
+            mStreamsByHandle.erase(it);
+        }
+    }
+    return serviceStream;
+}
+
+sp<AAudioServiceStreamBase> AAudioStreamTracker::getStreamByHandleAndIncrement(
         aaudio_handle_t streamHandle) {
     std::lock_guard<std::mutex> lock(mHandleLock);
     sp<AAudioServiceStreamBase> serviceStream;
     auto it = mStreamsByHandle.find(streamHandle);
     if (it != mStreamsByHandle.end()) {
         serviceStream = it->second;
-        mStreamsByHandle.erase(it);
+        serviceStream->incrementServiceReferenceCount_l();
     }
     return serviceStream;
 }
 
-sp<AAudioServiceStreamBase> AAudioStreamTracker::getStreamByHandle(
-        aaudio_handle_t streamHandle) {
-    std::lock_guard<std::mutex> lock(mHandleLock);
-    sp<AAudioServiceStreamBase> serviceStream;
-    auto it = mStreamsByHandle.find(streamHandle);
-    if (it != mStreamsByHandle.end()) {
-        serviceStream = it->second;
-    }
-    return serviceStream;
-}
-
-
 // The port handle is only available when the stream is started.
 // So we have to iterate over all the streams.
 // Luckily this rarely happens.
-sp<AAudioServiceStreamBase> AAudioStreamTracker::findStreamByPortHandle(
+sp<AAudioServiceStreamBase> AAudioStreamTracker::findStreamByPortHandleAndIncrement(
         audio_port_handle_t portHandle) {
     std::lock_guard<std::mutex> lock(mHandleLock);
     sp<AAudioServiceStreamBase> serviceStream;
@@ -66,6 +72,7 @@
         auto candidate = it->second;
         if (candidate->getPortHandle() == portHandle) {
             serviceStream = candidate;
+            serviceStream->incrementServiceReferenceCount_l();
             break;
         }
         it++;
@@ -86,7 +93,7 @@
 
 aaudio_handle_t AAudioStreamTracker::addStreamForHandle(sp<AAudioServiceStreamBase> serviceStream) {
     std::lock_guard<std::mutex> lock(mHandleLock);
-    aaudio_handle_t handle = mPreviousHandle.load();
+    aaudio_handle_t handle = mPreviousHandle;
     // Assign a unique handle.
     while (true) {
         handle = bumpHandle(handle);
@@ -98,7 +105,7 @@
             break;
         }
     }
-    mPreviousHandle.store(handle);
+    mPreviousHandle = handle;
     return handle;
 }
 
diff --git a/services/oboeservice/AAudioStreamTracker.h b/services/oboeservice/AAudioStreamTracker.h
index 54e46ca..57ec426 100644
--- a/services/oboeservice/AAudioStreamTracker.h
+++ b/services/oboeservice/AAudioStreamTracker.h
@@ -32,25 +32,35 @@
 
 public:
     /**
-     * Remove the stream associated with the handle.
+     * Find the stream associated with the handle.
+     * Decrement its reference counter. If zero and the stream needs
+     * to be closed then remove the stream and return a pointer to the stream.
+     * Otherwise return null if it does not need to be closed.
+     *
      * @param streamHandle
-     * @return strong pointer to the stream if found or to nullptr
+     * @return strong pointer to the stream if it needs to be closed, or nullptr
      */
-    android::sp<AAudioServiceStreamBase> removeStreamByHandle(aaudio_handle_t streamHandle);
+    android::sp<AAudioServiceStreamBase> decrementAndRemoveStreamByHandle(
+            aaudio_handle_t streamHandle);
 
     /**
      * Look up a stream based on the handle.
+     * Increment its service reference count if found.
+     *
      * @param streamHandle
-     * @return strong pointer to the stream if found or to nullptr
+     * @return strong pointer to the stream if found, or nullptr
      */
-    android::sp<aaudio::AAudioServiceStreamBase> getStreamByHandle(aaudio_handle_t streamHandle);
+    android::sp<aaudio::AAudioServiceStreamBase> getStreamByHandleAndIncrement(
+            aaudio_handle_t streamHandle);
 
     /**
      * Look up a stream based on the AudioPolicy portHandle.
+     * Increment its service reference count if found.
+     *
      * @param portHandle
-     * @return strong pointer to the stream if found or to nullptr
+     * @return strong pointer to the stream if found, or nullptr
      */
-    android::sp<aaudio::AAudioServiceStreamBase> findStreamByPortHandle(
+    android::sp<aaudio::AAudioServiceStreamBase> findStreamByPortHandleAndIncrement(
             audio_port_handle_t portHandle);
 
     /**
@@ -71,7 +81,9 @@
 
     // Track stream using a unique handle that wraps. Only use positive half.
     mutable std::mutex                mHandleLock;
-    std::atomic<aaudio_handle_t>      mPreviousHandle{0};
+    // protected by mHandleLock
+    aaudio_handle_t                   mPreviousHandle = 0;
+    // protected by mHandleLock
     std::map<aaudio_handle_t, android::sp<aaudio::AAudioServiceStreamBase>> mStreamsByHandle;
 };