Merge "BufferPool: Guarantee double-loadability" into rvc-dev
diff --git a/camera/ICameraClient.cpp b/camera/ICameraClient.cpp
index 8620f36..487b8b0 100644
--- a/camera/ICameraClient.cpp
+++ b/camera/ICameraClient.cpp
@@ -143,6 +143,11 @@
             if (data.dataAvail() > 0) {
                 metadata = new camera_frame_metadata_t;
                 metadata->number_of_faces = data.readInt32();
+                if (metadata->number_of_faces <= 0 ||
+                        metadata->number_of_faces > (int32_t)(INT32_MAX / sizeof(camera_face_t))) {
+                    ALOGE("%s: Too large face count: %d", __FUNCTION__, metadata->number_of_faces);
+                    return BAD_VALUE;
+                }
                 metadata->faces = (camera_face_t *) data.readInplace(
                         sizeof(camera_face_t) * metadata->number_of_faces);
             }
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmFactory.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmFactory.cpp
index ccc73b6..1ce8269 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DrmFactory.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmFactory.cpp
@@ -91,6 +91,19 @@
     return Void();
 }
 
+Return<void> DrmFactory::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& /*args*/) {
+    if (fd.getNativeHandle() == nullptr || fd->numFds < 1) {
+        ALOGE("%s: missing fd for writing", __FUNCTION__);
+        return Void();
+    }
+
+    FILE* out = fdopen(dup(fd->data[0]), "w");
+    uint32_t currentSessions = SessionLibrary::get()->numOpenSessions();
+    fprintf(out, "current open sessions: %u\n", currentSessions);
+    fclose(out);
+    return Void();
+}
+
 } // namespace clearkey
 } // namespace V1_3
 } // namespace drm
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/DrmFactory.h b/drm/mediadrm/plugins/clearkey/hidl/include/DrmFactory.h
index 403a8ec..63234cf 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/DrmFactory.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/DrmFactory.h
@@ -30,6 +30,7 @@
 
 using ::android::hardware::drm::V1_1::SecurityLevel;
 using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_handle;
 using ::android::hardware::hidl_string;
 using ::android::hardware::Return;
 
@@ -55,6 +56,8 @@
     Return<void> getSupportedCryptoSchemes(
             getSupportedCryptoSchemes_cb _hidl_cb) override;
 
+    Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args);
+
 private:
     CLEARKEY_DISALLOW_COPY_AND_ASSIGN(DrmFactory);
 };
diff --git a/media/TEST_MAPPING b/media/TEST_MAPPING
new file mode 100644
index 0000000..a6dfb21
--- /dev/null
+++ b/media/TEST_MAPPING
@@ -0,0 +1,32 @@
+{
+  "presubmit": [
+    {
+      "name": "GtsMediaTestCases",
+      "options" : [
+        {
+          "include-annotation": "android.platform.test.annotations.Presubmit"
+        },
+        {
+          "include-filter": "com.google.android.media.gts.WidevineGenericOpsTests"
+        }
+      ]
+    },
+    {
+      "name": "GtsExoPlayerTestCases",
+      "options" : [
+        {
+          "include-annotation": "android.platform.test.annotations.SocPresubmit"
+        },
+        {
+          "include-filter": "com.google.android.exoplayer.gts.DashTest#testWidevine23FpsH264Fixed"
+        }
+      ]
+    }
+  ],
+  "imports": [
+    {
+      "path": "frameworks/av/drm/mediadrm/plugins"
+    }
+  ]
+}
+
diff --git a/media/codec2/hidl/1.0/vts/functional/component/VtsHalMediaC2V1_0TargetComponentTest.cpp b/media/codec2/hidl/1.0/vts/functional/component/VtsHalMediaC2V1_0TargetComponentTest.cpp
index 119ce14..6122225 100644
--- a/media/codec2/hidl/1.0/vts/functional/component/VtsHalMediaC2V1_0TargetComponentTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/component/VtsHalMediaC2V1_0TargetComponentTest.cpp
@@ -330,7 +330,7 @@
 TEST_P(Codec2ComponentInputTests, InputBufferTest) {
     description("Tests for different inputs");
 
-    uint32_t flags = std::stol(std::get<2>(GetParam()));
+    uint32_t flags = std::stoul(std::get<2>(GetParam()));
     bool isNullBuffer = !std::get<3>(GetParam()).compare("true");
     if (isNullBuffer)
         ALOGD("Testing for null input buffer with flag : %u", flags);
diff --git a/media/codec2/hidl/client/client.cpp b/media/codec2/hidl/client/client.cpp
index 0acab49..7e4352d 100644
--- a/media/codec2/hidl/client/client.cpp
+++ b/media/codec2/hidl/client/client.cpp
@@ -219,6 +219,7 @@
                 if (success) {
                     break;
                 }
+                invalidate();
                 using namespace std::chrono_literals;
                 static constexpr auto kServiceRetryPeriod = 5s;
                 LOG(INFO) << "Failed to retrieve component traits from service "
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 6b389d5..e902b5d 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -44,6 +44,7 @@
 #include <media/stagefright/MediaCodecConstants.h>
 #include <media/stagefright/SkipCutBuffer.h>
 #include <media/MediaCodecBuffer.h>
+#include <mediadrm/ICrypto.h>
 #include <system/window.h>
 
 #include "CCodecBufferChannel.h"
@@ -1084,7 +1085,7 @@
                 // TODO: handle this without going into array mode
                 forceArrayMode = true;
             } else {
-                input->buffers.reset(new GraphicInputBuffers(numInputSlots, mName));
+                input->buffers.reset(new GraphicInputBuffers(mName));
             }
         } else {
             if (hasCryptoOrDescrambler()) {
@@ -1252,7 +1253,7 @@
             if (outputSurface || !buffersBoundToCodec) {
                 output->buffers.reset(new GraphicOutputBuffers(mName));
             } else {
-                output->buffers.reset(new RawGraphicOutputBuffers(numOutputSlots, mName));
+                output->buffers.reset(new RawGraphicOutputBuffers(mName));
             }
         } else {
             output->buffers.reset(new LinearOutputBuffers(mName));
diff --git a/media/codec2/sfplugin/CCodecBuffers.cpp b/media/codec2/sfplugin/CCodecBuffers.cpp
index d7cc175..a9120c4 100644
--- a/media/codec2/sfplugin/CCodecBuffers.cpp
+++ b/media/codec2/sfplugin/CCodecBuffers.cpp
@@ -23,6 +23,7 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaCodecConstants.h>
 #include <media/stagefright/SkipCutBuffer.h>
+#include <mediadrm/ICrypto.h>
 
 #include "CCodecBuffers.h"
 
@@ -121,6 +122,11 @@
 
 // OutputBuffers
 
+OutputBuffers::OutputBuffers(const char *componentName, const char *name)
+    : CCodecBuffers(componentName, name) { }
+
+OutputBuffers::~OutputBuffers() = default;
+
 void OutputBuffers::initSkipCutBuffer(
         int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount) {
     CHECK(mSkipCutBuffer == nullptr);
@@ -171,8 +177,11 @@
 
 // LocalBufferPool
 
-std::shared_ptr<LocalBufferPool> LocalBufferPool::Create(size_t poolCapacity) {
-    return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(poolCapacity));
+constexpr size_t kInitialPoolCapacity = kMaxLinearBufferSize;
+constexpr size_t kMaxPoolCapacity = kMaxLinearBufferSize * 32;
+
+std::shared_ptr<LocalBufferPool> LocalBufferPool::Create() {
+    return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(kInitialPoolCapacity));
 }
 
 sp<ABuffer> LocalBufferPool::newBuffer(size_t capacity) {
@@ -192,6 +201,11 @@
             mUsedSize -= mPool.back().capacity();
             mPool.pop_back();
         }
+        while (mUsedSize + capacity > mPoolCapacity && mPoolCapacity * 2 <= kMaxPoolCapacity) {
+            ALOGD("Increasing local buffer pool capacity from %zu to %zu",
+                  mPoolCapacity, mPoolCapacity * 2);
+            mPoolCapacity *= 2;
+        }
         if (mUsedSize + capacity > mPoolCapacity) {
             ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
                     mUsedSize, capacity, mPoolCapacity);
@@ -777,11 +791,10 @@
 // GraphicInputBuffers
 
 GraphicInputBuffers::GraphicInputBuffers(
-        size_t numInputSlots, const char *componentName, const char *name)
+        const char *componentName, const char *name)
     : InputBuffers(componentName, name),
       mImpl(mName),
-      mLocalBufferPool(LocalBufferPool::Create(
-              kMaxLinearBufferSize * numInputSlots)) { }
+      mLocalBufferPool(LocalBufferPool::Create()) { }
 
 bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
     sp<Codec2Buffer> newBuffer = createNewBuffer();
@@ -942,7 +955,7 @@
         case C2BufferData::GRAPHIC: {
             // This is only called for RawGraphicOutputBuffers.
             mAlloc = [format = mFormat,
-                      lbp = LocalBufferPool::Create(kMaxLinearBufferSize * mImpl.arraySize())] {
+                      lbp = LocalBufferPool::Create()] {
                 return ConstGraphicBlockBuffer::AllocateEmpty(
                         format,
                         [lbp](size_t capacity) {
@@ -1079,10 +1092,9 @@
 // RawGraphicOutputBuffers
 
 RawGraphicOutputBuffers::RawGraphicOutputBuffers(
-        size_t numOutputSlots, const char *componentName, const char *name)
+        const char *componentName, const char *name)
     : FlexOutputBuffers(componentName, name),
-      mLocalBufferPool(LocalBufferPool::Create(
-              kMaxLinearBufferSize * numOutputSlots)) { }
+      mLocalBufferPool(LocalBufferPool::Create()) { }
 
 sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
     if (buffer == nullptr) {
diff --git a/media/codec2/sfplugin/CCodecBuffers.h b/media/codec2/sfplugin/CCodecBuffers.h
index 85ca5d5..6244acd 100644
--- a/media/codec2/sfplugin/CCodecBuffers.h
+++ b/media/codec2/sfplugin/CCodecBuffers.h
@@ -28,6 +28,8 @@
 
 namespace android {
 
+struct ICrypto;
+class MemoryDealer;
 class SkipCutBuffer;
 
 constexpr size_t kLinearBufferSize = 1048576;
@@ -156,9 +158,8 @@
 
 class OutputBuffers : public CCodecBuffers {
 public:
-    OutputBuffers(const char *componentName, const char *name = "Output")
-        : CCodecBuffers(componentName, name) { }
-    virtual ~OutputBuffers() = default;
+    OutputBuffers(const char *componentName, const char *name = "Output");
+    virtual ~OutputBuffers();
 
     /**
      * Register output C2Buffer from the component and obtain corresponding
@@ -243,11 +244,9 @@
     /**
      * Create a new LocalBufferPool object.
      *
-     * \param poolCapacity  max total size of buffers managed by this pool.
-     *
      * \return  a newly created pool object.
      */
-    static std::shared_ptr<LocalBufferPool> Create(size_t poolCapacity);
+    static std::shared_ptr<LocalBufferPool> Create();
 
     /**
      * Return an ABuffer object whose size is at least |capacity|.
@@ -679,8 +678,7 @@
 
 class GraphicInputBuffers : public InputBuffers {
 public:
-    GraphicInputBuffers(
-            size_t numInputSlots, const char *componentName, const char *name = "2D-BB-Input");
+    GraphicInputBuffers(const char *componentName, const char *name = "2D-BB-Input");
     ~GraphicInputBuffers() override = default;
 
     bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override;
@@ -892,8 +890,7 @@
 
 class RawGraphicOutputBuffers : public FlexOutputBuffers {
 public:
-    RawGraphicOutputBuffers(
-            size_t numOutputSlots, const char *componentName, const char *name = "2D-BB-Output");
+    RawGraphicOutputBuffers(const char *componentName, const char *name = "2D-BB-Output");
     ~RawGraphicOutputBuffers() override = default;
 
     sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) override;
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index 5b3a62f..25e7da9 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -18,6 +18,8 @@
 #define LOG_TAG "Codec2Buffer"
 #include <utils/Log.h>
 
+#include <android/hardware/cas/native/1.0/types.h>
+#include <android/hardware/drm/1.0/types.h>
 #include <hidlmemory/FrameworkUtils.h>
 #include <media/hardware/HardwareAPI.h>
 #include <media/stagefright/CodecBase.h>
@@ -25,6 +27,7 @@
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AUtils.h>
+#include <mediadrm/ICrypto.h>
 #include <nativebase/nativebase.h>
 #include <ui/Fence.h>
 
diff --git a/media/codec2/sfplugin/Codec2Buffer.h b/media/codec2/sfplugin/Codec2Buffer.h
index ff79946..dc788cd 100644
--- a/media/codec2/sfplugin/Codec2Buffer.h
+++ b/media/codec2/sfplugin/Codec2Buffer.h
@@ -20,16 +20,29 @@
 
 #include <C2Buffer.h>
 
-#include <android/hardware/cas/native/1.0/types.h>
-#include <android/hardware/drm/1.0/types.h>
 #include <binder/IMemory.h>
 #include <media/hardware/VideoAPI.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/MediaCodecBuffer.h>
-#include <mediadrm/ICrypto.h>
 
 namespace android {
 
+namespace hardware {
+class HidlMemory;
+namespace cas {
+namespace native {
+namespace V1_0 {
+struct SharedBuffer;
+}  // namespace V1_0
+}  // namespace native
+}  // namespace cas
+namespace drm {
+namespace V1_0 {
+struct SharedBuffer;
+}  // namespace V1_0
+}  // namespace drm
+}  // namespace hardware
+
 /**
  * Copies a graphic view into a media image.
  *
diff --git a/media/codec2/sfplugin/tests/Android.bp b/media/codec2/sfplugin/tests/Android.bp
index fe5fa68..8d1a9c3 100644
--- a/media/codec2/sfplugin/tests/Android.bp
+++ b/media/codec2/sfplugin/tests/Android.bp
@@ -2,12 +2,13 @@
     name: "ccodec_unit_test",
 
     srcs: [
+        "CCodecBuffers_test.cpp",
         "CCodecConfig_test.cpp",
         "ReflectedParamUpdater_test.cpp",
     ],
 
     defaults: [
-        "libcodec2-hidl-defaults@1.0",
+        "libcodec2-impl-defaults",
         "libcodec2-internal-defaults",
     ],
 
@@ -16,14 +17,24 @@
     ],
 
     shared_libs: [
+        "android.hardware.media.bufferpool@2.0",
+        "android.hardware.media.c2@1.0",
         "libcodec2",
         "libcodec2_client",
+        "libhidlbase",
+        "libfmq",
+        "libmedia_omx",
         "libsfplugin_ccodec",
         "libsfplugin_ccodec_utils",
         "libstagefright_foundation",
         "libutils",
     ],
 
+    static_libs: [
+        "libcodec2_hidl@1.0",
+        "libstagefright_bufferpool@2.0",
+    ],
+
     cflags: [
         "-Werror",
         "-Wall",
diff --git a/media/codec2/sfplugin/tests/CCodecBuffers_test.cpp b/media/codec2/sfplugin/tests/CCodecBuffers_test.cpp
new file mode 100644
index 0000000..5bee605
--- /dev/null
+++ b/media/codec2/sfplugin/tests/CCodecBuffers_test.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CCodecBuffers.h"
+
+#include <gtest/gtest.h>
+
+#include <media/stagefright/MediaCodecConstants.h>
+
+#include <C2PlatformSupport.h>
+
+namespace android {
+
+TEST(RawGraphicOutputBuffersTest, ChangeNumSlots) {
+    constexpr int32_t kWidth = 3840;
+    constexpr int32_t kHeight = 2160;
+
+    std::shared_ptr<RawGraphicOutputBuffers> buffers =
+        std::make_shared<RawGraphicOutputBuffers>("test");
+    sp<AMessage> format{new AMessage};
+    format->setInt32("width", kWidth);
+    format->setInt32("height", kHeight);
+    buffers->setFormat(format);
+
+    std::shared_ptr<C2BlockPool> pool;
+    ASSERT_EQ(OK, GetCodec2BlockPool(C2BlockPool::BASIC_GRAPHIC, nullptr, &pool));
+
+    // Register 4 buffers
+    std::vector<sp<MediaCodecBuffer>> clientBuffers;
+    auto registerBuffer = [&buffers, &clientBuffers, &pool] {
+        std::shared_ptr<C2GraphicBlock> block;
+        ASSERT_EQ(OK, pool->fetchGraphicBlock(
+                kWidth, kHeight, HAL_PIXEL_FORMAT_YCbCr_420_888,
+                C2MemoryUsage{C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}, &block));
+        std::shared_ptr<C2Buffer> c2Buffer = C2Buffer::CreateGraphicBuffer(block->share(
+                block->crop(), C2Fence{}));
+        size_t index;
+        sp<MediaCodecBuffer> clientBuffer;
+        ASSERT_EQ(OK, buffers->registerBuffer(c2Buffer, &index, &clientBuffer));
+        ASSERT_NE(nullptr, clientBuffer);
+        while (clientBuffers.size() <= index) {
+            clientBuffers.emplace_back();
+        }
+        ASSERT_EQ(nullptr, clientBuffers[index]) << "index = " << index;
+        clientBuffers[index] = clientBuffer;
+    };
+    for (int i = 0; i < 4; ++i) {
+        registerBuffer();
+    }
+
+    // Release 2 buffers
+    auto releaseBuffer = [&buffers, &clientBuffers, kWidth, kHeight](int index) {
+        std::shared_ptr<C2Buffer> c2Buffer;
+        ASSERT_TRUE(buffers->releaseBuffer(clientBuffers[index], &c2Buffer))
+                << "index = " << index;
+        clientBuffers[index] = nullptr;
+        // Sanity checks
+        ASSERT_TRUE(c2Buffer->data().linearBlocks().empty());
+        ASSERT_EQ(1u, c2Buffer->data().graphicBlocks().size());
+        C2ConstGraphicBlock block = c2Buffer->data().graphicBlocks().front();
+        ASSERT_EQ(kWidth, block.width());
+        ASSERT_EQ(kHeight, block.height());
+    };
+    for (int i = 0, index = 0; i < 2 && index < clientBuffers.size(); ++index) {
+        if (clientBuffers[index] == nullptr) {
+            continue;
+        }
+        releaseBuffer(index);
+        ++i;
+    }
+
+    // Simulate # of slots 4->16
+    for (int i = 2; i < 16; ++i) {
+        registerBuffer();
+    }
+
+    // Release everything
+    for (int index = 0; index < clientBuffers.size(); ++index) {
+        if (clientBuffers[index] == nullptr) {
+            continue;
+        }
+        releaseBuffer(index);
+    }
+}
+
+} // namespace android
diff --git a/media/codec2/vndk/C2AllocatorGralloc.cpp b/media/codec2/vndk/C2AllocatorGralloc.cpp
index 3ac3d89..e1e1377 100644
--- a/media/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/codec2/vndk/C2AllocatorGralloc.cpp
@@ -520,6 +520,22 @@
             break;
         }
 
+        case static_cast<uint32_t>(PixelFormat4::BLOB): {
+            void *pointer = nullptr;
+            // TODO: fence
+            status_t err = GraphicBufferMapper::get().lock(
+                                const_cast<native_handle_t*>(mBuffer), grallocUsage,
+                                { (int32_t)rect.left, (int32_t)rect.top,
+                                  (int32_t)rect.width, (int32_t)rect.height },
+                                &pointer);
+            if (err) {
+                ALOGE("failed transaction: lock(BLOB)");
+                return C2_CORRUPTED;
+            }
+            *addr = (uint8_t *)pointer;
+            break;
+        }
+
         case static_cast<uint32_t>(PixelFormat4::YCBCR_420_888):
             // fall-through
         case static_cast<uint32_t>(PixelFormat4::YV12):
diff --git a/media/extractors/midi/Android.bp b/media/extractors/midi/Android.bp
index bdb724b..b8255fc 100644
--- a/media/extractors/midi/Android.bp
+++ b/media/extractors/midi/Android.bp
@@ -10,7 +10,7 @@
 
     static_libs: [
         "libmedia_midiiowrapper",
-        "libsonivox",
+        "libsonivoxwithoutjet",
         "libstagefright_foundation",
         "libwatchdog",
     ],
diff --git a/media/extractors/tests/Android.bp b/media/extractors/tests/Android.bp
index fa39b64..b3afe2f 100644
--- a/media/extractors/tests/Android.bp
+++ b/media/extractors/tests/Android.bp
@@ -45,7 +45,7 @@
         "libstagefright_metadatautils",
 
         "libmedia_midiiowrapper",
-        "libsonivox",
+        "libsonivoxwithoutjet",
         "libvorbisidec",
         "libwebm",
         "libFLAC",
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index edc09a9..a47f189 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -406,6 +406,7 @@
      * Use this preset for capturing audio meant to be processed in real time
      * and played back for live performance (e.g karaoke).
      * The capture path will minimize latency and coupling with playback path.
+     * Available since API level 29.
      */
     AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE = 10,
 };
diff --git a/media/libaaudio/src/Android.bp b/media/libaaudio/src/Android.bp
index 901c28f..717f31a 100644
--- a/media/libaaudio/src/Android.bp
+++ b/media/libaaudio/src/Android.bp
@@ -35,6 +35,9 @@
         "libaaudio_internal",
         "libaudioclient",
         "libaudioutils",
+        "libmedia_helper",
+        "libmediametrics",
+        "libmediautils",
         "liblog",
         "libcutils",
         "libutils",
@@ -75,6 +78,9 @@
     shared_libs: [
         "libaudioclient",
         "libaudioutils",
+        "libmedia_helper",
+        "libmediametrics",
+        "libmediautils",
         "liblog",
         "libcutils",
         "libutils",
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index f89cde7..3db0099 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -14,9 +14,7 @@
  * limitations under the License.
  */
 
-// This file is used in both client and server processes.
-// This is needed to make sense of the logs more easily.
-#define LOG_TAG (mInService ? "AudioStreamInternal_Service" : "AudioStreamInternal_Client")
+#define LOG_TAG "AudioStreamInternal"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -28,6 +26,8 @@
 
 #include <aaudio/AAudio.h>
 #include <cutils/properties.h>
+
+#include <media/MediaMetricsItem.h>
 #include <utils/String16.h>
 #include <utils/Trace.h>
 
@@ -36,12 +36,20 @@
 #include "binding/AAudioStreamConfiguration.h"
 #include "binding/IAAudioService.h"
 #include "binding/AAudioServiceMessage.h"
+#include "core/AudioGlobal.h"
 #include "core/AudioStreamBuilder.h"
 #include "fifo/FifoBuffer.h"
 #include "utility/AudioClock.h"
 
 #include "AudioStreamInternal.h"
 
+// We do this after the #includes because if a header uses ALOG.
+// it would fail on the reference to mInService.
+#undef LOG_TAG
+// This file is used in both client and server processes.
+// This is needed to make sense of the logs more easily.
+#define LOG_TAG (mInService ? "AudioStreamInternal_Service" : "AudioStreamInternal_Client")
+
 using android::String16;
 using android::Mutex;
 using android::WrappingBuffer;
@@ -137,6 +145,11 @@
         return mServiceStreamHandle;
     }
 
+    // This must match the key generated in oboeservice/AAudioServiceStreamBase.cpp
+    // so the client can have permission to log.
+    mMetricsId = std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM)
+            + std::to_string(mServiceStreamHandle);
+
     result = configurationOutput.validate();
     if (result != AAUDIO_OK) {
         goto error;
@@ -274,6 +287,9 @@
         if (isActive() || currentState == AAUDIO_STREAM_STATE_DISCONNECTED) {
             requestStop();
         }
+
+        logBufferState();
+
         setState(AAUDIO_STREAM_STATE_CLOSING);
         aaudio_handle_t serviceStreamHandle = mServiceStreamHandle;
         mServiceStreamHandle = AAUDIO_HANDLE_INVALID;
diff --git a/media/libaaudio/src/core/AudioGlobal.cpp b/media/libaaudio/src/core/AudioGlobal.cpp
index d299761..7f5d8d5 100644
--- a/media/libaaudio/src/core/AudioGlobal.cpp
+++ b/media/libaaudio/src/core/AudioGlobal.cpp
@@ -71,7 +71,42 @@
         AAUDIO_CASE_ENUM(AAUDIO_ERROR_NO_SERVICE);
         AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_RATE);
     }
-    return "Unrecognized AAudio error.";
+    return "Unrecognized";
+}
+
+const char* AudioGlobal_convertFormatToText(aaudio_format_t format) {
+      switch (format) {
+        AAUDIO_CASE_ENUM(AAUDIO_FORMAT_UNSPECIFIED);
+        AAUDIO_CASE_ENUM(AAUDIO_FORMAT_INVALID);
+        AAUDIO_CASE_ENUM(AAUDIO_FORMAT_PCM_I16);
+        AAUDIO_CASE_ENUM(AAUDIO_FORMAT_PCM_FLOAT);
+    }
+    return "Unrecognized";
+}
+
+const char* AudioGlobal_convertDirectionToText(aaudio_direction_t direction) {
+      switch (direction) {
+        AAUDIO_CASE_ENUM(AAUDIO_DIRECTION_INPUT);
+        AAUDIO_CASE_ENUM(AAUDIO_DIRECTION_OUTPUT);
+    }
+    return "Unrecognized";
+}
+
+const char* AudioGlobal_convertPerformanceModeToText(aaudio_performance_mode_t mode) {
+      switch (mode) {
+        AAUDIO_CASE_ENUM(AAUDIO_PERFORMANCE_MODE_POWER_SAVING);
+        AAUDIO_CASE_ENUM(AAUDIO_PERFORMANCE_MODE_NONE);
+        AAUDIO_CASE_ENUM(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
+    }
+    return "Unrecognized";
+}
+
+const char* AudioGlobal_convertSharingModeToText(aaudio_sharing_mode_t mode) {
+      switch (mode) {
+        AAUDIO_CASE_ENUM(AAUDIO_SHARING_MODE_SHARED);
+        AAUDIO_CASE_ENUM(AAUDIO_SHARING_MODE_EXCLUSIVE);
+    }
+    return "Unrecognized";
 }
 
 const char* AudioGlobal_convertStreamStateToText(aaudio_stream_state_t state) {
@@ -91,7 +126,7 @@
         AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_CLOSED);
         AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_DISCONNECTED);
     }
-    return "Unrecognized AAudio state.";
+    return "Unrecognized";
 }
 
 #undef AAUDIO_CASE_ENUM
diff --git a/media/libaaudio/src/core/AudioGlobal.h b/media/libaaudio/src/core/AudioGlobal.h
index 312cef2..1e88d15 100644
--- a/media/libaaudio/src/core/AudioGlobal.h
+++ b/media/libaaudio/src/core/AudioGlobal.h
@@ -25,9 +25,12 @@
 aaudio_policy_t AudioGlobal_getMMapPolicy();
 aaudio_result_t AudioGlobal_setMMapPolicy(aaudio_policy_t policy);
 
+const char* AudioGlobal_convertFormatToText(aaudio_format_t format);
+const char* AudioGlobal_convertDirectionToText(aaudio_direction_t direction);
+const char* AudioGlobal_convertPerformanceModeToText(aaudio_performance_mode_t mode);
 const char* AudioGlobal_convertResultToText(aaudio_result_t returnCode);
+const char* AudioGlobal_convertSharingModeToText(aaudio_sharing_mode_t mode);
 const char* AudioGlobal_convertStreamStateToText(aaudio_stream_state_t state);
-
 }
 
 #endif  // AAUDIO_AUDIOGLOBAL_H
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index 4252dfd..0644368 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -20,6 +20,9 @@
 
 #include <atomic>
 #include <stdint.h>
+
+#include <media/MediaMetricsItem.h>
+
 #include <aaudio/AAudio.h>
 
 #include "AudioStreamBuilder.h"
@@ -29,7 +32,6 @@
 
 namespace aaudio {
 
-
 // Sequential number assigned to streams solely for debugging purposes.
 static aaudio_stream_id_t AAudio_getNextStreamId() {
     static std::atomic <aaudio_stream_id_t> nextStreamId{1};
@@ -103,6 +105,26 @@
     return AAUDIO_OK;
 }
 
+void AudioStream::logOpen() {
+    if (mMetricsId.size() > 0) {
+        android::mediametrics::LogItem(mMetricsId)
+                .set(AMEDIAMETRICS_PROP_PERFORMANCEMODE,
+                     AudioGlobal_convertPerformanceModeToText(getPerformanceMode()))
+                .set(AMEDIAMETRICS_PROP_SHARINGMODE,
+                     AudioGlobal_convertSharingModeToText(getSharingMode()))
+                .record();
+    }
+}
+
+void AudioStream::logBufferState() {
+    if (mMetricsId.size() > 0) {
+        android::mediametrics::LogItem(mMetricsId)
+                .set(AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES, (int32_t) getBufferSize())
+                .set(AMEDIAMETRICS_PROP_UNDERRUN, (int32_t) getXRunCount())
+                .record();
+    }
+}
+
 aaudio_result_t AudioStream::systemStart() {
     std::lock_guard<std::mutex> lock(mStreamLock);
 
@@ -291,6 +313,13 @@
 
 void AudioStream::setState(aaudio_stream_state_t state) {
     ALOGD("%s(s#%d) from %d to %d", __func__, getId(), mState, state);
+    // Track transition to DISCONNECTED state.
+    if (state == AAUDIO_STREAM_STATE_DISCONNECTED && mState != state) {
+        android::mediametrics::LogItem(mMetricsId)
+                .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_DISCONNECT)
+                .set(AMEDIAMETRICS_PROP_STATE, AudioGlobal_convertStreamStateToText(getState()))
+                .record();
+    }
     // CLOSED is a final state
     if (mState == AAUDIO_STREAM_STATE_CLOSED) {
         ALOGE("%s(%d) tried to set to %d but already CLOSED", __func__, getId(), state);
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index 9bda41b..613a092 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -95,7 +95,6 @@
                                        int64_t *framePosition,
                                        int64_t *timeNanoseconds) = 0;
 
-
     /**
      * Update state machine.()
      * @return
@@ -114,6 +113,10 @@
      */
     virtual aaudio_result_t open(const AudioStreamBuilder& builder);
 
+    // log to MediaMetrics
+    virtual void logOpen();
+    void logBufferState();
+
     /**
      * Free any hardware or system resources from the open() call.
      * It is safe to call release_l() multiple times.
@@ -573,6 +576,8 @@
         mIsPrivacySensitive = privacySensitive;
     }
 
+    std::string mMetricsId; // set once during open()
+
 private:
 
     aaudio_result_t safeStop();
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index 3a1e1c9..60dad84 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -193,10 +193,14 @@
                         *streamPtr = audioStream;
                     } else {
                         delete audioStream;
+                        audioStream = nullptr;
                     }
                 }
             }
         }
+        if (audioStream != nullptr) {
+            audioStream->logOpen();
+        }
     }
 
     return result;
diff --git a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
index abc3239..c062882 100644
--- a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
@@ -26,6 +26,7 @@
 #include <media/AudioTimestamp.h>
 #include <utils/String16.h>
 
+#include "core/AudioGlobal.h"
 #include "core/AudioStream.h"
 #include "legacy/AudioStreamLegacy.h"
 
diff --git a/media/libaaudio/src/legacy/AudioStreamLegacy.h b/media/libaaudio/src/legacy/AudioStreamLegacy.h
index da9205f..9c24b2b 100644
--- a/media/libaaudio/src/legacy/AudioStreamLegacy.h
+++ b/media/libaaudio/src/legacy/AudioStreamLegacy.h
@@ -128,6 +128,10 @@
         return mFramesRead.increment(frames);
     }
 
+    // This is used for exact matching by MediaMetrics. So do not change it.
+    // MediaMetricsConstants.h: AMEDIAMETRICS_PROP_CALLERNAME_VALUE_AAUDIO
+    static constexpr char     kCallerName[] = "aaudio";
+
     MonotonicCounter           mFramesWritten;
     MonotonicCounter           mFramesRead;
     MonotonicCounter           mTimestampPosition;
@@ -139,6 +143,7 @@
     const android::sp<StreamDeviceCallback>   mDeviceCallback;
 
     AtomicRequestor            mRequestDisconnect;
+
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index 904edd1..853c0db 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -179,6 +179,9 @@
                 selectedDeviceId
         );
 
+        // Set it here so it can be logged by the destructor if the open failed.
+        mAudioRecord->setCallerName(kCallerName);
+
         // Did we get a valid track?
         status_t status = mAudioRecord->initCheck();
         if (status != OK) {
@@ -202,6 +205,9 @@
         }
     }
 
+    mMetricsId = std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD)
+            + std::to_string(mAudioRecord->getPortId());
+
     // Get the actual values from the AudioRecord.
     setSamplesPerFrame(mAudioRecord->channelCount());
 
@@ -286,6 +292,7 @@
     //  Then call it from here
     if (getState() != AAUDIO_STREAM_STATE_CLOSING) {
         mAudioRecord->removeAudioDeviceCallback(mDeviceCallback);
+        logBufferState();
         mAudioRecord.clear();
         mFixedBlockWriter.close();
         return AudioStream::release_l();
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 6da63e8..1120f05 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -173,6 +173,9 @@
             selectedDeviceId
     );
 
+    // Set it here so it can be logged by the destructor if the open failed.
+    mAudioTrack->setCallerName(kCallerName);
+
     // Did we get a valid track?
     status_t status = mAudioTrack->initCheck();
     if (status != NO_ERROR) {
@@ -181,6 +184,9 @@
         return AAudioConvert_androidToAAudioResult(status);
     }
 
+    mMetricsId = std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
+            + std::to_string(mAudioTrack->getPortId());
+
     doSetVolume();
 
     // Get the actual values from the AudioTrack.
@@ -248,6 +254,7 @@
 aaudio_result_t AudioStreamTrack::release_l() {
     if (getState() != AAUDIO_STREAM_STATE_CLOSING) {
         mAudioTrack->removeAudioDeviceCallback(mDeviceCallback);
+        logBufferState();
         // TODO Investigate why clear() causes a hang in test_various.cpp
         // if I call close() from a data callback.
         // But the same thing in AudioRecord is OK!
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index fc50e07..0bbceef 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -170,6 +170,10 @@
 
     mediametrics::LogItem(mMetricsId)
         .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_DTOR)
+        .set(AMEDIAMETRICS_PROP_CALLERNAME,
+                mCallerName.empty()
+                ? AMEDIAMETRICS_PROP_CALLERNAME_VALUE_UNKNOWN
+                : mCallerName.c_str())
         .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)mStatus)
         .record();
 
@@ -396,6 +400,10 @@
     status_t status = NO_ERROR;
     mediametrics::Defer defer([&] {
         mediametrics::LogItem(mMetricsId)
+            .set(AMEDIAMETRICS_PROP_CALLERNAME,
+                    mCallerName.empty()
+                    ? AMEDIAMETRICS_PROP_CALLERNAME_VALUE_UNKNOWN
+                    : mCallerName.c_str())
             .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_START)
             .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
             .set(AMEDIAMETRICS_PROP_STATE, stateToString(mActive))
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 8b357a3..ca80dc4 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -301,6 +301,10 @@
 
     mediametrics::LogItem(mMetricsId)
         .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_DTOR)
+        .set(AMEDIAMETRICS_PROP_CALLERNAME,
+                mCallerName.empty()
+                ? AMEDIAMETRICS_PROP_CALLERNAME_VALUE_UNKNOWN
+                : mCallerName.c_str())
         .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
         .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)mStatus)
         .record();
@@ -641,6 +645,10 @@
     status_t status = NO_ERROR; // logged: make sure to set this before returning.
     mediametrics::Defer defer([&] {
         mediametrics::LogItem(mMetricsId)
+            .set(AMEDIAMETRICS_PROP_CALLERNAME,
+                    mCallerName.empty()
+                    ? AMEDIAMETRICS_PROP_CALLERNAME_VALUE_UNKNOWN
+                    : mCallerName.c_str())
             .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_START)
             .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
             .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
@@ -777,7 +785,9 @@
             .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_STOP)
             .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
             .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
-            .record(); });
+            .record();
+        logBufferSizeUnderruns();
+    });
 
     ALOGV("%s(%d): prior state:%s", __func__, mPortId, stateToString(mState));
 
@@ -873,7 +883,7 @@
 {
     const int64_t beginNs = systemTime();
     AutoMutex lock(mLock);
-    mediametrics::Defer([&]() {
+    mediametrics::Defer defer([&]() {
         mediametrics::LogItem(mMetricsId)
             .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_PAUSE)
             .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
@@ -1107,6 +1117,7 @@
     if (mOutput == AUDIO_IO_HANDLE_NONE || mProxy.get() == 0) {
         return NO_INIT;
     }
+
     return (ssize_t) mProxy->getBufferSizeInFrames();
 }
 
@@ -1128,6 +1139,16 @@
     return NO_ERROR;
 }
 
+void AudioTrack::logBufferSizeUnderruns() {
+    LOG_ALWAYS_FATAL_IF(mMetricsId.size() == 0, "mMetricsId is empty!");
+    ALOGD("%s(), mMetricsId = %s", __func__, mMetricsId.c_str());
+    // FIXME THis hangs! Why?
+//    android::mediametrics::LogItem(mMetricsId)
+//            .set(AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES, (int32_t) getBufferSizeInFrames())
+//            .set(AMEDIAMETRICS_PROP_UNDERRUN, (int32_t) getUnderrunCount())
+//            .record();
+}
+
 ssize_t AudioTrack::setBufferSizeInFrames(size_t bufferSizeInFrames)
 {
     AutoMutex lock(mLock);
@@ -1138,7 +1159,13 @@
     if (!audio_is_linear_pcm(mFormat)) {
         return INVALID_OPERATION;
     }
-    return (ssize_t) mProxy->setBufferSizeInFrames((uint32_t) bufferSizeInFrames);
+
+    ssize_t originalBufferSize = mProxy->getBufferSizeInFrames();
+    ssize_t finalBufferSize  = mProxy->setBufferSizeInFrames((uint32_t) bufferSizeInFrames);
+    if (originalBufferSize != finalBufferSize) {
+        logBufferSizeUnderruns();
+    }
+    return finalBufferSize;
 }
 
 status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount)
@@ -2410,7 +2437,7 @@
 {
     status_t result = NO_ERROR;  // logged: make sure to set this before returning.
     const int64_t beginNs = systemTime();
-    mediametrics::Defer([&] {
+    mediametrics::Defer defer([&] {
         mediametrics::LogItem(mMetricsId)
             .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_RESTORE)
             .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
diff --git a/media/libaudioclient/ToneGenerator.cpp b/media/libaudioclient/ToneGenerator.cpp
index 536b00d..050ad65 100644
--- a/media/libaudioclient/ToneGenerator.cpp
+++ b/media/libaudioclient/ToneGenerator.cpp
@@ -1262,7 +1262,9 @@
             AUDIO_UID_INVALID,
             -1,
             &attr);
-
+    // Set caller name so it can be logged in destructor.
+    // MediaMetricsConstants.h: AMEDIAMETRICS_PROP_CALLERNAME_VALUE_TONEGENERATOR
+    mpAudioTrack->setCallerName("tonegenerator");
     if (status != NO_ERROR) {
         ALOGE("AudioTrack(%p) set failed with error %d", mpAudioTrack.get(), status);
         mpAudioTrack.clear();
diff --git a/media/libaudioclient/include/media/AudioRecord.h b/media/libaudioclient/include/media/AudioRecord.h
index b3c1cdf..2f66658 100644
--- a/media/libaudioclient/include/media/AudioRecord.h
+++ b/media/libaudioclient/include/media/AudioRecord.h
@@ -277,6 +277,19 @@
      */
             status_t getMetrics(mediametrics::Item * &item);
 
+    /*
+     * Set name of API that is using this object.
+     * For example "aaudio" or "opensles".
+     * This may be logged or reported as part of MediaMetrics.
+     */
+            void setCallerName(const std::string &name) {
+                mCallerName = name;
+            }
+
+            std::string getCallerName() const {
+                return mCallerName;
+            };
+
     /* After it's created the track is not active. Call start() to
      * make it active. If set, the callback will start being called.
      * If event is not AudioSystem::SYNC_EVENT_NONE, the capture start will be delayed until
@@ -776,6 +789,7 @@
     };
     MediaMetrics mMediaMetrics;
     std::string mMetricsId;  // GUARDED_BY(mLock), could change in createRecord_l().
+    std::string mCallerName; // for example "aaudio"
 };
 
 }; // namespace android
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index afae4d8..17af7d4 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -410,6 +410,19 @@
      */
             status_t getMetrics(mediametrics::Item * &item);
 
+    /*
+     * Set name of API that is using this object.
+     * For example "aaudio" or "opensles".
+     * This may be logged or reported as part of MediaMetrics.
+     */
+            void setCallerName(const std::string &name) {
+                mCallerName = name;
+            }
+
+            std::string getCallerName() const {
+                return mCallerName;
+            };
+
     /* After it's created the track is not active. Call start() to
      * make it active. If set, the callback will start being called.
      * If the track was previously paused, volume is ramped up over the first mix buffer.
@@ -1259,6 +1272,9 @@
     };
     MediaMetrics mMediaMetrics;
     std::string mMetricsId;  // GUARDED_BY(mLock), could change in createTrack_l().
+    std::string mCallerName; // for example "aaudio"
+
+    void logBufferSizeUnderruns();
 
 private:
     class AudioTrackCallback : public media::BnAudioTrackCallback {
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 62a86e7..be3f995 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -187,7 +187,7 @@
     srcs: ["MidiIoWrapper.cpp"],
 
     static_libs: [
-        "libsonivox",
+        "libsonivoxwithoutjet",
     ],
 
     header_libs: [
@@ -312,7 +312,7 @@
         "libutils",
         "libbinder",
         "libbinder_ndk",
-        "libsonivox",
+        //"libsonivox",
         "libandroidicu",
         "libexpat",
         "libcamera_client",
@@ -328,7 +328,7 @@
         "libaudioclient",
         "libbinder",
         "libandroidicu",
-        "libsonivox",
+        //"libsonivox",
         "libmedia_omx",
     ],
 
diff --git a/media/libmedia/aidl/android/media/IResourceManagerService.aidl b/media/libmedia/aidl/android/media/IResourceManagerService.aidl
index 3dd0859..1b2d522 100644
--- a/media/libmedia/aidl/android/media/IResourceManagerService.aidl
+++ b/media/libmedia/aidl/android/media/IResourceManagerService.aidl
@@ -94,4 +94,12 @@
      *        remove existing override on originalPid if newPid is -1.
      */
     void overridePid(int originalPid, int newPid);
+
+    /**
+     * Mark a client for pending removal
+     *
+     * @param pid pid from which the client's resources will be removed.
+     * @param clientId clientId within the pid that will be removed.
+     */
+    void markClientForPendingRemoval(int pid, long clientId);
 }
diff --git a/media/libmediametrics/include/MediaMetricsConstants.h b/media/libmediametrics/include/MediaMetricsConstants.h
index eb7ac7d..00da69a 100644
--- a/media/libmediametrics/include/MediaMetricsConstants.h
+++ b/media/libmediametrics/include/MediaMetricsConstants.h
@@ -40,6 +40,9 @@
 // The AudioRecord key appends the "trackId" to the prefix.
 #define AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD AMEDIAMETRICS_KEY_PREFIX_AUDIO "record."
 
+// The AudioStream key appends the "streamId" to the prefix.
+#define AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM  AMEDIAMETRICS_KEY_PREFIX_AUDIO "stream."
+
 // The AudioThread key appends the "threadId" to the prefix.
 #define AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD AMEDIAMETRICS_KEY_PREFIX_AUDIO "thread."
 
@@ -83,10 +86,16 @@
 // of suppressed in the Time Machine.
 #define AMEDIAMETRICS_PROP_SUFFIX_CHAR_DUPLICATES_ALLOWED '#'
 
+#define AMEDIAMETRICS_PROP_ALLOWUID       "_allowUid"      // int32_t, allow client uid to post
 #define AMEDIAMETRICS_PROP_AUXEFFECTID    "auxEffectId"    // int32 (AudioTrack)
+#define AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES "bufferSizeFrames" // int32
+#define AMEDIAMETRICS_PROP_BUFFERCAPACITYFRAMES "bufferCapacityFrames" // int32
+#define AMEDIAMETRICS_PROP_BURSTFRAMES    "burstFrames"    // int32
+#define AMEDIAMETRICS_PROP_CALLERNAME     "callerName"     // string, eg. "aaudio"
 #define AMEDIAMETRICS_PROP_CHANNELCOUNT   "channelCount"   // int32
 #define AMEDIAMETRICS_PROP_CHANNELMASK    "channelMask"    // int32
 #define AMEDIAMETRICS_PROP_CONTENTTYPE    "contentType"    // string attributes (AudioTrack)
+#define AMEDIAMETRICS_PROP_DIRECTION      "direction"      // string AAudio input or output
 #define AMEDIAMETRICS_PROP_DURATIONNS     "durationNs"     // int64 duration time span
 #define AMEDIAMETRICS_PROP_ENCODING       "encoding"       // string value of format
 #define AMEDIAMETRICS_PROP_EVENT          "event#"         // string value (often func name)
@@ -99,6 +108,7 @@
 #define AMEDIAMETRICS_PROP_LATENCYMS      "latencyMs"      // double value
 #define AMEDIAMETRICS_PROP_ORIGINALFLAGS  "originalFlags"  // int32
 #define AMEDIAMETRICS_PROP_OUTPUTDEVICES  "outputDevices"  // string value
+#define AMEDIAMETRICS_PROP_PERFORMANCEMODE "performanceMode"    // string value, "none", lowLatency"
 #define AMEDIAMETRICS_PROP_PLAYBACK_PITCH "playback.pitch" // double value (AudioTrack)
 #define AMEDIAMETRICS_PROP_PLAYBACK_SPEED "playback.speed" // double value (AudioTrack)
 #define AMEDIAMETRICS_PROP_ROUTEDDEVICEID "routedDeviceId" // int32
@@ -107,6 +117,7 @@
 #define AMEDIAMETRICS_PROP_SELECTEDMICDIRECTION "selectedMicDirection" // int32
 #define AMEDIAMETRICS_PROP_SELECTEDMICFIELDDIRECTION "selectedMicFieldDimension" // double
 #define AMEDIAMETRICS_PROP_SESSIONID      "sessionId"      // int32
+#define AMEDIAMETRICS_PROP_SHARINGMODE    "sharingMode"    // string value, "exclusive", shared"
 #define AMEDIAMETRICS_PROP_SOURCE         "source"         // string (AudioAttributes)
 #define AMEDIAMETRICS_PROP_STARTUPMS      "startupMs"      // double value
 // State is "ACTIVE" or "STOPPED" for AudioRecord
@@ -129,12 +140,15 @@
 // Values are strings accepted for a given property.
 
 // An event is a general description, which often is a function name.
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_CLOSE      "close"
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE     "create"
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_CREATEAUDIOPATCH "createAudioPatch"
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR       "ctor"
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_DISCONNECT "disconnect"
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_DTOR       "dtor"
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_FLUSH      "flush"  // AudioTrack
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_INVALIDATE "invalidate" // server track, record
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_OPEN       "open"
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_PAUSE      "pause"  // AudioTrack
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_READPARAMETERS "readParameters" // Thread
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_RESTORE    "restore"
@@ -144,4 +158,16 @@
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_STOP       "stop"   // AudioTrack, AudioRecord
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_UNDERRUN   "underrun" // from Thread
 
+// Possible values for AMEDIAMETRICS_PROP_CALLERNAME
+// Check within the framework for these strings as this header file may not be explicitly
+// included to avoid unnecessary cross-project dependencies.
+#define AMEDIAMETRICS_PROP_CALLERNAME_VALUE_AAUDIO        "aaudio"         // Native AAudio
+#define AMEDIAMETRICS_PROP_CALLERNAME_VALUE_JAVA          "java"           // Java API layer
+#define AMEDIAMETRICS_PROP_CALLERNAME_VALUE_MEDIA         "media"          // libmedia
+#define AMEDIAMETRICS_PROP_CALLERNAME_VALUE_OPENSLES      "opensles"       // Open SLES
+#define AMEDIAMETRICS_PROP_CALLERNAME_VALUE_RTP           "rtp"            // RTP communication
+#define AMEDIAMETRICS_PROP_CALLERNAME_VALUE_SOUNDPOOL     "soundpool"      // SoundPool
+#define AMEDIAMETRICS_PROP_CALLERNAME_VALUE_TONEGENERATOR "tonegenerator"  // dial tones
+#define AMEDIAMETRICS_PROP_CALLERNAME_VALUE_UNKNOWN       "unknown"        // callerName not set
+
 #endif // ANDROID_MEDIA_MEDIAMETRICSCONSTANTS_H
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 42a0622..c0da0ce 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -2206,7 +2206,9 @@
                     targetSpeed,
                     mSelectedDeviceId);
         }
-
+        // Set caller name so it can be logged in destructor.
+        // MediaMetricsConstants.h: AMEDIAMETRICS_PROP_CALLERNAME_VALUE_MEDIA
+        t->setCallerName("media");
         if ((t == 0) || (t->initCheck() != NO_ERROR)) {
             ALOGE("Unable to create audio track");
             delete newcbd;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 73d3a0b..63ab654 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -2053,17 +2053,34 @@
     if (mIsVideo || mIsImage) {
         // determine need for software renderer
         bool usingSwRenderer = false;
-        if (haveNativeWindow && mComponentName.startsWith("OMX.google.")) {
-            usingSwRenderer = true;
-            haveNativeWindow = false;
-            (void)setPortMode(kPortIndexOutput, IOMX::kPortModePresetByteBuffer);
-        } else if (haveNativeWindow && !storingMetadataInDecodedBuffers()) {
-            err = setPortMode(kPortIndexOutput, IOMX::kPortModePresetANWBuffer);
-            if (err != OK) {
-                return err;
+        if (haveNativeWindow) {
+            bool requiresSwRenderer = false;
+            OMX_PARAM_U32TYPE param;
+            InitOMXParams(&param);
+            param.nPortIndex = kPortIndexOutput;
+
+            status_t err = mOMXNode->getParameter(
+                    (OMX_INDEXTYPE)OMX_IndexParamVideoAndroidRequiresSwRenderer,
+                    &param, sizeof(param));
+
+            if (err == OK && param.nU32 == 1) {
+                requiresSwRenderer = true;
             }
+
+            if (mComponentName.startsWith("OMX.google.") || requiresSwRenderer) {
+                usingSwRenderer = true;
+                haveNativeWindow = false;
+                (void)setPortMode(kPortIndexOutput, IOMX::kPortModePresetByteBuffer);
+            } else if (!storingMetadataInDecodedBuffers()) {
+                err = setPortMode(kPortIndexOutput, IOMX::kPortModePresetANWBuffer);
+                if (err != OK) {
+                    return err;
+                }
+            }
+
         }
 
+
         if (encoder) {
             err = setupVideoEncoder(mime, msg, outputFormat, inputFormat);
         } else {
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index 00c5b40..4bc861e 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -108,6 +108,9 @@
                     selectedDeviceId,
                     selectedMicDirection,
                     selectedMicFieldDimension);
+        // Set caller name so it can be logged in destructor.
+        // MediaMetricsConstants.h: AMEDIAMETRICS_PROP_CALLERNAME_VALUE_MEDIA
+        mRecord->setCallerName("media");
         mInitCheck = mRecord->initCheck();
         if (mInitCheck != OK) {
             mRecord.clear();
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index b597583..11f2f38 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -199,6 +199,7 @@
     void addResource(const MediaResourceParcel &resource);
     void removeResource(const MediaResourceParcel &resource);
     void removeClient();
+    void markClientForPendingRemoval();
     bool reclaimResource(const std::vector<MediaResourceParcel> &resources);
 
 private:
@@ -280,6 +281,14 @@
     mService->removeClient(mPid, getId(mClient));
 }
 
+void MediaCodec::ResourceManagerServiceProxy::markClientForPendingRemoval() {
+    Mutex::Autolock _l(mLock);
+    if (mService == nullptr) {
+        return;
+    }
+    mService->markClientForPendingRemoval(mPid, getId(mClient));
+}
+
 bool MediaCodec::ResourceManagerServiceProxy::reclaimResource(
         const std::vector<MediaResourceParcel> &resources) {
     Mutex::Autolock _l(mLock);
@@ -297,6 +306,33 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
+class MediaCodec::ReleaseSurface {
+public:
+    ReleaseSurface() {
+        BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+        mSurface = new Surface(mProducer, false /* controlledByApp */);
+        struct ConsumerListener : public BnConsumerListener {
+            void onFrameAvailable(const BufferItem&) override {}
+            void onBuffersReleased() override {}
+            void onSidebandStreamChanged() override {}
+        };
+        sp<ConsumerListener> listener{new ConsumerListener};
+        mConsumer->consumerConnect(listener, false);
+        mConsumer->setConsumerName(String8{"MediaCodec.release"});
+    }
+
+    const sp<Surface> &getSurface() {
+        return mSurface;
+    }
+
+private:
+    sp<IGraphicBufferProducer> mProducer;
+    sp<IGraphicBufferConsumer> mConsumer;
+    sp<Surface> mSurface;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
 namespace {
 
 enum {
@@ -1432,7 +1468,13 @@
 
 status_t MediaCodec::release() {
     sp<AMessage> msg = new AMessage(kWhatRelease, this);
+    sp<AMessage> response;
+    return PostAndAwaitResponse(msg, &response);
+}
 
+status_t MediaCodec::releaseAsync() {
+    sp<AMessage> msg = new AMessage(kWhatRelease, this);
+    msg->setInt32("async", 1);
     sp<AMessage> response;
     return PostAndAwaitResponse(msg, &response);
 }
@@ -2600,7 +2642,9 @@
 
                     mResourceManagerProxy->removeClient();
 
-                    (new AMessage)->postReply(mReplyID);
+                    if (mReplyID != nullptr) {
+                        (new AMessage)->postReply(mReplyID);
+                    }
                     break;
                 }
 
@@ -2987,6 +3031,26 @@
                 break;
             }
 
+            int32_t async = 0;
+            if (msg->findInt32("async", &async) && async) {
+                if ((mState ==  CONFIGURED || mState == STARTED || mState == FLUSHED)
+                       && mSurface != NULL) {
+                    if (!mReleaseSurface) {
+                        mReleaseSurface.reset(new ReleaseSurface);
+                    }
+                    status_t err = connectToSurface(mReleaseSurface->getSurface());
+                    ALOGW_IF(err != OK, "error connecting to release surface: err = %d", err);
+                    if (err == OK && !(mFlags & kFlagUsesSoftwareRenderer)) {
+                        err = mCodec->setSurface(mReleaseSurface->getSurface());
+                        ALOGW_IF(err != OK, "error setting release surface: err = %d", err);
+                    }
+                    if (err == OK) {
+                        (void)disconnectFromSurface();
+                        mSurface = mReleaseSurface->getSurface();
+                    }
+                }
+            }
+
             mReplyID = replyID;
             setState(msg->what() == kWhatStop ? STOPPING : RELEASING);
 
@@ -2999,6 +3063,12 @@
                 pushBlankBuffersToNativeWindow(mSurface.get());
             }
 
+            if (async) {
+                mResourceManagerProxy->markClientForPendingRemoval();
+                (new AMessage)->postReply(mReplyID);
+                mReplyID = 0;
+            }
+
             break;
         }
 
diff --git a/media/libstagefright/MediaExtractorFactory.cpp b/media/libstagefright/MediaExtractorFactory.cpp
index 94267a1..c6e753d 100644
--- a/media/libstagefright/MediaExtractorFactory.cpp
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -302,6 +302,12 @@
 #endif
             "/extractors", NULL, *newList);
 
+    RegisterExtractors("/system_ext/lib"
+#ifdef __LP64__
+            "64"
+#endif
+            "/extractors", NULL, *newList);
+
     newList->sort(compareFunc);
     gPlugins = newList;
 
diff --git a/media/libstagefright/codecs/amrwb/src/pvamrwbdecoder.cpp b/media/libstagefright/codecs/amrwb/src/pvamrwbdecoder.cpp
index ddc818e..c9c1cd4 100644
--- a/media/libstagefright/codecs/amrwb/src/pvamrwbdecoder.cpp
+++ b/media/libstagefright/codecs/amrwb/src/pvamrwbdecoder.cpp
@@ -337,7 +337,10 @@
     st = (Decoder_State *) spd_state;
 
     /* mode verification */
-
+    if (mode < 0 || mode >= NUM_OF_MODES)
+    {
+        return (-1);
+    }
     nb_bits = AMR_WB_COMPRESSED[mode];
 
     *frame_length = AMR_WB_PCM_FRAME;
diff --git a/media/libstagefright/foundation/OpusHeader.cpp b/media/libstagefright/foundation/OpusHeader.cpp
index f5687e0..784e802 100644
--- a/media/libstagefright/foundation/OpusHeader.cpp
+++ b/media/libstagefright/foundation/OpusHeader.cpp
@@ -126,12 +126,20 @@
     }
     header->num_streams = data[kOpusHeaderNumStreamsOffset];
     header->num_coupled = data[kOpusHeaderNumCoupledStreamsOffset];
-    if (header->num_streams + header->num_coupled != header->channels) {
-        ALOGV("Inconsistent channel mapping.");
+    if (header->num_coupled > header->num_streams ||
+        header->num_streams + header->num_coupled != header->channels) {
+        ALOGV("Inconsistent channel mapping, streams: %d coupled: %d channels: %d",
+        header->num_streams, header->num_coupled, header->channels);
         return false;
     }
-    for (int i = 0; i < header->channels; ++i)
-        header->stream_map[i] = data[kOpusHeaderStreamMapOffset + i];
+    for (int i = 0; i < header->channels; ++i) {
+        uint8_t value = data[kOpusHeaderStreamMapOffset + i];
+        if (value != 255 && value >= header->channels) {
+            ALOGV("Invalid channel mapping for index %i : %d", i, value);
+            return false;
+        }
+        header->stream_map[i] = value;
+    }
     return true;
 }
 
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index 022c48e..63a9dad 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -139,6 +139,8 @@
     // object.
     status_t release();
 
+    status_t releaseAsync();
+
     status_t flush();
 
     status_t queueInputBuffer(
@@ -509,6 +511,9 @@
                                                  // when low latency is on
     int64_t mInputBufferCounter;  // number of input buffers queued since last reset/flush
 
+    class ReleaseSurface;
+    std::unique_ptr<ReleaseSurface> mReleaseSurface;
+
     sp<BatteryChecker> mBatteryChecker;
 
     void statsBufferSent(int64_t presentationUs);
diff --git a/services/audioflinger/FastThread.cpp b/services/audioflinger/FastThread.cpp
index 8b7a124..47fe0b3 100644
--- a/services/audioflinger/FastThread.cpp
+++ b/services/audioflinger/FastThread.cpp
@@ -309,7 +309,7 @@
                     // compute the delta value of clock_gettime(CLOCK_MONOTONIC)
                     uint32_t monotonicNs = nsec;
                     if (sec > 0 && sec < 4) {
-                        monotonicNs += sec * 1000000000;
+                        monotonicNs += sec * 1000000000U; // unsigned to prevent signed overflow.
                     }
                     // compute raw CPU load = delta value of clock_gettime(CLOCK_THREAD_CPUTIME_ID)
                     uint32_t loadNs = 0;
@@ -325,7 +325,7 @@
                             }
                             loadNs = nsec;
                             if (sec > 0 && sec < 4) {
-                                loadNs += sec * 1000000000;
+                                loadNs += sec * 1000000000U; // unsigned to prevent signed overflow.
                             }
                         } else {
                             // first time through the loop
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 105fa14..5d9c35a 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -3051,6 +3051,10 @@
 {
     if (!mMasterMute) {
         char value[PROPERTY_VALUE_MAX];
+        if (mOutDeviceTypeAddrs.empty()) {
+            ALOGD("ro.audio.silent is ignored since no output device is set");
+            return;
+        }
         if (isSingleDeviceType(outDeviceTypes(), AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) {
             ALOGD("ro.audio.silent will be ignored for threads on AUDIO_DEVICE_OUT_REMOTE_SUBMIX");
             return;
@@ -4227,6 +4231,7 @@
                          (mPatch.sinks[0].id != sinkPortId);
     mPatch = *patch;
     mOutDeviceTypeAddrs = deviceTypeAddrs;
+    checkSilentMode_l();
 
     if (mOutput->audioHwDev->supportsAudioPatches()) {
         sp<DeviceHalInterface> hwDevice = mOutput->audioHwDev->hwDevice();
@@ -9153,6 +9158,7 @@
         if (isOutput()) {
             sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
             mOutDeviceTypeAddrs = sinkDeviceTypeAddrs;
+            checkSilentMode_l();
         } else {
             sendIoConfigEvent_l(AUDIO_INPUT_CONFIG_CHANGED);
             mInDeviceTypeAddr = sourceDeviceTypeAddr;
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 23d8329..4898d37 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -605,6 +605,7 @@
     mediametrics::LogItem(mMetricsId)
         .setPid(creatorPid)
         .setUid(uid)
+        .set(AMEDIAMETRICS_PROP_ALLOWUID, (int32_t)uid)
         .set(AMEDIAMETRICS_PROP_EVENT,
                 AMEDIAMETRICS_PROP_PREFIX_SERVER AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR)
         .record();
@@ -2165,6 +2166,7 @@
     mediametrics::LogItem(mMetricsId)
         .setPid(creatorPid)
         .setUid(uid)
+        .set(AMEDIAMETRICS_PROP_ALLOWUID, (int32_t)uid)
         .set(AMEDIAMETRICS_PROP_EVENT, "server." AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR)
         .record();
 }
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
index a757551..b82305d 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
@@ -72,8 +72,8 @@
      */
     status_t getOutputForAttr(const audio_attributes_t& attributes, uid_t uid,
                               audio_output_flags_t flags,
-                              sp<SwAudioOutputDescriptor> &primaryDesc,
-                              std::vector<sp<SwAudioOutputDescriptor>> *secondaryDescs);
+                              sp<AudioPolicyMix> &primaryMix,
+                              std::vector<sp<AudioPolicyMix>> *secondaryMixes);
 
     sp<DeviceDescriptor> getDeviceAndMixForInputSource(audio_source_t inputSource,
                                                        const DeviceVector &availableDeviceTypes,
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index ed51389..fc1a59f 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -150,11 +150,11 @@
 status_t AudioPolicyMixCollection::getOutputForAttr(
         const audio_attributes_t& attributes, uid_t uid,
         audio_output_flags_t flags,
-        sp<SwAudioOutputDescriptor> &primaryDesc,
-        std::vector<sp<SwAudioOutputDescriptor>> *secondaryDescs)
+        sp<AudioPolicyMix> &primaryMix,
+        std::vector<sp<AudioPolicyMix>> *secondaryMixes)
 {
     ALOGV("getOutputForAttr() querying %zu mixes:", size());
-    primaryDesc = 0;
+    primaryMix.clear();
     for (size_t i = 0; i < size(); i++) {
         sp<AudioPolicyMix> policyMix = itemAt(i);
         const bool primaryOutputMix = !is_mix_loopback_render(policyMix->mRouteFlags);
@@ -169,13 +169,7 @@
             return INVALID_OPERATION;
         }
 
-        sp<SwAudioOutputDescriptor> policyDesc = policyMix->getOutput();
-        if (!policyDesc) {
-            ALOGV("%s: Skiping %zu: Mix has no output", __func__, i);
-            continue;
-        }
-
-        if (primaryOutputMix && primaryDesc != 0) {
+        if (primaryOutputMix && primaryMix != nullptr) {
             ALOGV("%s: Skiping %zu: Primary output already found", __func__, i);
             continue; // Primary output already found
         }
@@ -191,18 +185,13 @@
             case MixMatchStatus::MATCH:;
         }
 
-        policyDesc->mPolicyMix = policyMix;
         if (primaryOutputMix) {
-            primaryDesc = policyDesc;
+            primaryMix = policyMix;
             ALOGV("%s: Mix %zu: set primary desc", __func__, i);
         } else {
-            if (policyDesc->mIoHandle == AUDIO_IO_HANDLE_NONE) {
-                ALOGV("%s: Mix %zu ignored as secondaryOutput because not opened yet", __func__, i);
-            } else {
-                ALOGV("%s: Add a secondary desc %zu", __func__, i);
-                if (secondaryDescs != nullptr) {
-                    secondaryDescs->push_back(policyDesc);
-                }
+            ALOGV("%s: Add a secondary desc %zu", __func__, i);
+            if (secondaryMixes != nullptr) {
+                secondaryMixes->push_back(policyMix);
             }
         }
     }
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index 886e4c9..d31e443 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -320,7 +320,7 @@
 {
     String8 devAddress = (address == nullptr || !matchAddress) ? String8("") : String8(address);
     // handle legacy remote submix case where the address was not always specified
-    if (device_distinguishes_on_address(deviceType) && (devAddress.length() == 0)) {
+    if (audio_is_remote_submix_device(deviceType) && (devAddress.length() == 0)) {
         devAddress = String8("0");
     }
 
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index f1c2ab5..bcf6f38 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -907,7 +907,7 @@
         audio_output_flags_t *flags,
         audio_port_handle_t *selectedDeviceId,
         bool *isRequestedDeviceForExclusiveUse,
-        std::vector<sp<SwAudioOutputDescriptor>> *secondaryDescs,
+        std::vector<sp<AudioPolicyMix>> *secondaryMixes,
         output_type_t *outputType)
 {
     DeviceVector outputDevices;
@@ -932,29 +932,45 @@
     // The primary output is the explicit routing (eg. setPreferredDevice) if specified,
     //       otherwise, fallback to the dynamic policies, if none match, query the engine.
     // Secondary outputs are always found by dynamic policies as the engine do not support them
-    sp<SwAudioOutputDescriptor> policyDesc;
-    status = mPolicyMixes.getOutputForAttr(*resultAttr, uid, *flags, policyDesc, secondaryDescs);
+    sp<AudioPolicyMix> primaryMix;
+    status = mPolicyMixes.getOutputForAttr(*resultAttr, uid, *flags, primaryMix, secondaryMixes);
     if (status != OK) {
         return status;
     }
 
     // Explicit routing is higher priority then any dynamic policy primary output
-    bool usePrimaryOutputFromPolicyMixes = requestedDevice == nullptr && policyDesc != nullptr;
+    bool usePrimaryOutputFromPolicyMixes = requestedDevice == nullptr && primaryMix != nullptr;
 
     // FIXME: in case of RENDER policy, the output capabilities should be checked
-    if ((usePrimaryOutputFromPolicyMixes || !secondaryDescs->empty())
+    if ((usePrimaryOutputFromPolicyMixes
+            || (secondaryMixes != nullptr && !secondaryMixes->empty()))
         && !audio_is_linear_pcm(config->format)) {
         ALOGD("%s: rejecting request as dynamic audio policy only support pcm", __func__);
         return BAD_VALUE;
     }
     if (usePrimaryOutputFromPolicyMixes) {
-        *output = policyDesc->mIoHandle;
-        sp<AudioPolicyMix> mix = policyDesc->mPolicyMix.promote();
-        if (mix != nullptr) {
-            sp<DeviceDescriptor> deviceDesc =
-                    mAvailableOutputDevices.getDevice(mix->mDeviceType,
-                                                      mix->mDeviceAddress,
-                                                      AUDIO_FORMAT_DEFAULT);
+        sp<DeviceDescriptor> deviceDesc =
+                mAvailableOutputDevices.getDevice(primaryMix->mDeviceType,
+                                                  primaryMix->mDeviceAddress,
+                                                  AUDIO_FORMAT_DEFAULT);
+        sp<SwAudioOutputDescriptor> policyDesc = primaryMix->getOutput();
+        if (deviceDesc != nullptr
+                && (policyDesc == nullptr || (policyDesc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT))) {
+            audio_io_handle_t newOutput;
+            status = openDirectOutput(
+                    *stream, session, config,
+                    (audio_output_flags_t)(*flags | AUDIO_OUTPUT_FLAG_DIRECT),
+                    DeviceVector(deviceDesc), &newOutput);
+            if (status != NO_ERROR) {
+                policyDesc = nullptr;
+            } else {
+                policyDesc = mOutputs.valueFor(newOutput);
+                primaryMix->setOutput(policyDesc);
+            }
+        }
+        if (policyDesc != nullptr) {
+            policyDesc->mPolicyMix = primaryMix;
+            *output = policyDesc->mIoHandle;
             *selectedDeviceId = deviceDesc != 0 ? deviceDesc->getId() : AUDIO_PORT_HANDLE_NONE;
 
             ALOGV("getOutputForAttr() returns output %d", *output);
@@ -1050,7 +1066,7 @@
     const audio_port_handle_t requestedPortId = *selectedDeviceId;
     audio_attributes_t resultAttr;
     bool isRequestedDeviceForExclusiveUse = false;
-    std::vector<sp<SwAudioOutputDescriptor>> secondaryOutputDescs;
+    std::vector<sp<AudioPolicyMix>> secondaryMixes;
     const sp<DeviceDescriptor> requestedDevice =
       mAvailableOutputDevices.getDeviceFromId(requestedPortId);
 
@@ -1061,14 +1077,20 @@
 
     status_t status = getOutputForAttrInt(&resultAttr, output, session, attr, stream, uid,
             config, flags, selectedDeviceId, &isRequestedDeviceForExclusiveUse,
-            &secondaryOutputDescs, outputType);
+            secondaryOutputs != nullptr ? &secondaryMixes : nullptr, outputType);
     if (status != NO_ERROR) {
         return status;
     }
     std::vector<wp<SwAudioOutputDescriptor>> weakSecondaryOutputDescs;
-    for (auto& secondaryDesc : secondaryOutputDescs) {
-        secondaryOutputs->push_back(secondaryDesc->mIoHandle);
-        weakSecondaryOutputDescs.push_back(secondaryDesc);
+    if (secondaryOutputs != nullptr) {
+        for (auto &secondaryMix : secondaryMixes) {
+            sp<SwAudioOutputDescriptor> outputDesc = secondaryMix->getOutput();
+            if (outputDesc != nullptr &&
+                outputDesc->mIoHandle != AUDIO_IO_HANDLE_NONE) {
+                secondaryOutputs->push_back(outputDesc->mIoHandle);
+                weakSecondaryOutputDescs.push_back(outputDesc);
+            }
+        }
     }
 
     audio_config_base_t clientConfig = {.sample_rate = config->sample_rate,
@@ -1093,6 +1115,118 @@
     return NO_ERROR;
 }
 
+status_t AudioPolicyManager::openDirectOutput(audio_stream_type_t stream,
+                                              audio_session_t session,
+                                              const audio_config_t *config,
+                                              audio_output_flags_t flags,
+                                              const DeviceVector &devices,
+                                              audio_io_handle_t *output) {
+
+    *output = AUDIO_IO_HANDLE_NONE;
+
+    // skip direct output selection if the request can obviously be attached to a mixed output
+    // and not explicitly requested
+    if (((flags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) &&
+            audio_is_linear_pcm(config->format) && config->sample_rate <= SAMPLE_RATE_HZ_MAX &&
+            audio_channel_count_from_out_mask(config->channel_mask) <= 2) {
+        return NAME_NOT_FOUND;
+    }
+
+    // Do not allow offloading if one non offloadable effect is enabled or MasterMono is enabled.
+    // This prevents creating an offloaded track and tearing it down immediately after start
+    // when audioflinger detects there is an active non offloadable effect.
+    // FIXME: We should check the audio session here but we do not have it in this context.
+    // This may prevent offloading in rare situations where effects are left active by apps
+    // in the background.
+    sp<IOProfile> profile;
+    if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) ||
+            !(mEffects.isNonOffloadableEffectEnabled() || mMasterMono)) {
+        profile = getProfileForOutput(
+                devices, config->sample_rate, config->format, config->channel_mask,
+                flags, true /* directOnly */);
+    }
+
+    if (profile == nullptr) {
+        return NAME_NOT_FOUND;
+    }
+
+    // exclusive outputs for MMAP and Offload are enforced by different session ids.
+    for (size_t i = 0; i < mOutputs.size(); i++) {
+        sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
+        if (!desc->isDuplicated() && (profile == desc->mProfile)) {
+            // reuse direct output if currently open by the same client
+            // and configured with same parameters
+            if ((config->sample_rate == desc->getSamplingRate()) &&
+                (config->format == desc->getFormat()) &&
+                (config->channel_mask == desc->getChannelMask()) &&
+                (session == desc->mDirectClientSession)) {
+                desc->mDirectOpenCount++;
+                ALOGI("%s reusing direct output %d for session %d", __func__,
+                    mOutputs.keyAt(i), session);
+                *output = mOutputs.keyAt(i);
+                return NO_ERROR;
+            }
+        }
+    }
+
+    if (!profile->canOpenNewIo()) {
+        return NAME_NOT_FOUND;
+    }
+
+    sp<SwAudioOutputDescriptor> outputDesc =
+            new SwAudioOutputDescriptor(profile, mpClientInterface);
+
+    String8 address = getFirstDeviceAddress(devices);
+
+    // MSD patch may be using the only output stream that can service this request. Release
+    // MSD patch to prioritize this request over any active output on MSD.
+    AudioPatchCollection msdPatches = getMsdPatches();
+    for (size_t i = 0; i < msdPatches.size(); i++) {
+        const auto& patch = msdPatches[i];
+        for (size_t j = 0; j < patch->mPatch.num_sinks; ++j) {
+            const struct audio_port_config *sink = &patch->mPatch.sinks[j];
+            if (sink->type == AUDIO_PORT_TYPE_DEVICE &&
+                    devices.containsDeviceWithType(sink->ext.device.type) &&
+                    (address.isEmpty() || strncmp(sink->ext.device.address, address.string(),
+                            AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0)) {
+                releaseAudioPatch(patch->getHandle(), mUidCached);
+                break;
+            }
+        }
+    }
+
+    status_t status = outputDesc->open(config, devices, stream, flags, output);
+
+    // only accept an output with the requested parameters
+    if (status != NO_ERROR ||
+        (config->sample_rate != 0 && config->sample_rate != outputDesc->getSamplingRate()) ||
+        (config->format != AUDIO_FORMAT_DEFAULT && config->format != outputDesc->getFormat()) ||
+        (config->channel_mask != 0 && config->channel_mask != outputDesc->getChannelMask())) {
+        ALOGV("%s failed opening direct output: output %d sample rate %d %d,"
+                "format %d %d, channel mask %04x %04x", __func__, *output, config->sample_rate,
+                outputDesc->getSamplingRate(), config->format, outputDesc->getFormat(),
+                config->channel_mask, outputDesc->getChannelMask());
+        if (*output != AUDIO_IO_HANDLE_NONE) {
+            outputDesc->close();
+        }
+        // fall back to mixer output if possible when the direct output could not be open
+        if (audio_is_linear_pcm(config->format) &&
+                config->sample_rate  <= SAMPLE_RATE_HZ_MAX) {
+            return NAME_NOT_FOUND;
+        }
+        *output = AUDIO_IO_HANDLE_NONE;
+        return BAD_VALUE;
+    }
+    outputDesc->mDirectOpenCount = 1;
+    outputDesc->mDirectClientSession = session;
+
+    addOutput(*output, outputDesc);
+    mPreviousOutputs = mOutputs;
+    ALOGV("%s returns new direct output %d", __func__, *output);
+    mpClientInterface->onAudioPortListUpdate();
+    return NO_ERROR;
+}
+
 audio_io_handle_t AudioPolicyManager::getOutputForDevices(
         const DeviceVector &devices,
         audio_session_t session,
@@ -1102,7 +1236,6 @@
         bool forceMutingHaptic)
 {
     audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
-    status_t status;
 
     // Discard haptic channel mask when forcing muting haptic channels.
     audio_channel_mask_t channelMask = forceMutingHaptic
@@ -1137,112 +1270,13 @@
         ALOGV("Set VoIP and Direct output flags for PCM format");
     }
 
-
-    sp<IOProfile> profile;
-
-    // skip direct output selection if the request can obviously be attached to a mixed output
-    // and not explicitly requested
-    if (((*flags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) &&
-            audio_is_linear_pcm(config->format) && config->sample_rate <= SAMPLE_RATE_HZ_MAX &&
-            audio_channel_count_from_out_mask(channelMask) <= 2) {
-        goto non_direct_output;
-    }
-
-    // Do not allow offloading if one non offloadable effect is enabled or MasterMono is enabled.
-    // This prevents creating an offloaded track and tearing it down immediately after start
-    // when audioflinger detects there is an active non offloadable effect.
-    // FIXME: We should check the audio session here but we do not have it in this context.
-    // This may prevent offloading in rare situations where effects are left active by apps
-    // in the background.
-
-    if (((*flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) ||
-            !(mEffects.isNonOffloadableEffectEnabled() || mMasterMono)) {
-        profile = getProfileForOutput(devices,
-                                   config->sample_rate,
-                                   config->format,
-                                   channelMask,
-                                   (audio_output_flags_t)*flags,
-                                   true /* directOnly */);
-    }
-
-    if (profile != 0) {
-        // exclusive outputs for MMAP and Offload are enforced by different session ids.
-        for (size_t i = 0; i < mOutputs.size(); i++) {
-            sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
-            if (!desc->isDuplicated() && (profile == desc->mProfile)) {
-                // reuse direct output if currently open by the same client
-                // and configured with same parameters
-                if ((config->sample_rate == desc->getSamplingRate()) &&
-                    (config->format == desc->getFormat()) &&
-                    (channelMask == desc->getChannelMask()) &&
-                    (session == desc->mDirectClientSession)) {
-                    desc->mDirectOpenCount++;
-                    ALOGI("%s reusing direct output %d for session %d", __func__, 
-                        mOutputs.keyAt(i), session);
-                    return mOutputs.keyAt(i);
-                }
-            }
-        }
-
-        if (!profile->canOpenNewIo()) {
-            goto non_direct_output;
-        }
-
-        sp<SwAudioOutputDescriptor> outputDesc =
-                new SwAudioOutputDescriptor(profile, mpClientInterface);
-
-        String8 address = getFirstDeviceAddress(devices);
-
-        // MSD patch may be using the only output stream that can service this request. Release
-        // MSD patch to prioritize this request over any active output on MSD.
-        AudioPatchCollection msdPatches = getMsdPatches();
-        for (size_t i = 0; i < msdPatches.size(); i++) {
-            const auto& patch = msdPatches[i];
-            for (size_t j = 0; j < patch->mPatch.num_sinks; ++j) {
-                const struct audio_port_config *sink = &patch->mPatch.sinks[j];
-                if (sink->type == AUDIO_PORT_TYPE_DEVICE &&
-                        devices.containsDeviceWithType(sink->ext.device.type) &&
-                        (address.isEmpty() || strncmp(sink->ext.device.address, address.string(),
-                                AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0)) {
-                    releaseAudioPatch(patch->getHandle(), mUidCached);
-                    break;
-                }
-            }
-        }
-
-        status = outputDesc->open(config, devices, stream, *flags, &output);
-
-        // only accept an output with the requested parameters
-        if (status != NO_ERROR ||
-            (config->sample_rate != 0 && config->sample_rate != outputDesc->getSamplingRate()) ||
-            (config->format != AUDIO_FORMAT_DEFAULT && config->format != outputDesc->getFormat()) ||
-            (channelMask != 0 && channelMask != outputDesc->getChannelMask())) {
-            ALOGV("%s failed opening direct output: output %d sample rate %d %d," 
-                    "format %d %d, channel mask %04x %04x", __func__, output, config->sample_rate,
-                    outputDesc->getSamplingRate(), config->format, outputDesc->getFormat(),
-                    channelMask, outputDesc->getChannelMask());
-            if (output != AUDIO_IO_HANDLE_NONE) {
-                outputDesc->close();
-            }
-            // fall back to mixer output if possible when the direct output could not be open
-            if (audio_is_linear_pcm(config->format) &&
-                    config->sample_rate  <= SAMPLE_RATE_HZ_MAX) {
-                goto non_direct_output;
-            }
-            return AUDIO_IO_HANDLE_NONE;
-        }
-        outputDesc->mDirectOpenCount = 1;
-        outputDesc->mDirectClientSession = session;
-
-        addOutput(output, outputDesc);
-        mPreviousOutputs = mOutputs;
-        ALOGV("%s returns new direct output %d", __func__, output);
-        mpClientInterface->onAudioPortListUpdate();
+    audio_config_t directConfig = *config;
+    directConfig.channel_mask = channelMask;
+    status_t status = openDirectOutput(stream, session, &directConfig, *flags, devices, &output);
+    if (status != NAME_NOT_FOUND) {
         return output;
     }
 
-non_direct_output:
-
     // A request for HW A/V sync cannot fallback to a mixed output because time
     // stamps are embedded in audio data
     if ((*flags & (AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_MMAP_NOIRQ)) != 0) {
@@ -2146,7 +2180,7 @@
 
     if (!profile->canOpenNewIo()) {
         for (size_t i = 0; i < mInputs.size(); ) {
-            sp <AudioInputDescriptor> desc = mInputs.valueAt(i);
+            sp<AudioInputDescriptor> desc = mInputs.valueAt(i);
             if (desc->mProfile != profile) {
                 i++;
                 continue;
@@ -2886,8 +2920,8 @@
             }
             audio_config_t outputConfig = mix.mFormat;
             audio_config_t inputConfig = mix.mFormat;
-            // NOTE: audio flinger mixer does not support mono output: configure remote submix HAL in
-            // stereo and let audio flinger do the channel conversion if needed.
+            // NOTE: audio flinger mixer does not support mono output: configure remote submix HAL
+            // in stereo and let audio flinger do the channel conversion if needed.
             outputConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
             inputConfig.channel_mask = AUDIO_CHANNEL_IN_STEREO;
             rSubmixModule->addOutputProfile(address.c_str(), &outputConfig,
@@ -2917,10 +2951,11 @@
             }
 
             bool foundOutput = false;
-            for (size_t j = 0 ; j < mOutputs.size() ; j++) {
+            // First try to find an already opened output supporting the device
+            for (size_t j = 0 ; j < mOutputs.size() && !foundOutput && res == NO_ERROR; j++) {
                 sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(j);
 
-                if (desc->supportedDevices().contains(device)) {
+                if (!desc->isDuplicated() && desc->supportedDevices().contains(device)) {
                     if (mPolicyMixes.registerMix(mix, desc) != NO_ERROR) {
                         ALOGE("Could not register mix RENDER,  dev=0x%X addr=%s", type,
                               address.string());
@@ -2928,10 +2963,26 @@
                     } else {
                         foundOutput = true;
                     }
-                    break;
                 }
             }
-
+            // If no output found, try to find a direct output profile supporting the device
+            for (size_t i = 0; i < mHwModules.size() && !foundOutput && res == NO_ERROR; i++) {
+                sp<HwModule> module = mHwModules[i];
+                for (size_t j = 0;
+                        j < module->getOutputProfiles().size() && !foundOutput && res == NO_ERROR;
+                        j++) {
+                    sp<IOProfile> profile = module->getOutputProfiles()[j];
+                    if (profile->isDirectOutput() && profile->supportsDevice(device)) {
+                        if (mPolicyMixes.registerMix(mix, nullptr) != NO_ERROR) {
+                            ALOGE("Could not register mix RENDER,  dev=0x%X addr=%s", type,
+                                  address.string());
+                            res = INVALID_OPERATION;
+                        } else {
+                            foundOutput = true;
+                        }
+                    }
+                }
+            }
             if (res != NO_ERROR) {
                 ALOGE(" Error registering mix %zu for device 0x%X addr %s",
                         i, type, address.string());
@@ -3014,58 +3065,67 @@
     }
 }
 
+// Returns true if all devices types match the predicate and are supported by one HW module
+bool  AudioPolicyManager::areAllDevicesSupported(
+        const Vector<AudioDeviceTypeAddr>& devices,
+        std::function<bool(audio_devices_t)> predicate,
+        const char *context) {
+    for (size_t i = 0; i < devices.size(); i++) {
+        sp<DeviceDescriptor> devDesc = mHwModules.getDeviceDescriptor(
+                devices[i].mType, devices[i].mAddress.c_str(), String8(),
+                AUDIO_FORMAT_DEFAULT, false /*allowToCreate*/, true /*matchAddress*/);
+        if (devDesc == nullptr || (predicate != nullptr && !predicate(devices[i].mType))) {
+            ALOGE("%s: device type %#x address %s not supported or not an output device",
+                    context, devices[i].mType, devices[i].mAddress.c_str());
+            return false;
+        }
+    }
+    return true;
+}
+
 status_t AudioPolicyManager::setUidDeviceAffinities(uid_t uid,
         const Vector<AudioDeviceTypeAddr>& devices) {
     ALOGV("%s() uid=%d num devices %zu", __FUNCTION__, uid, devices.size());
-    // uid/device affinity is only for output devices
-    for (size_t i = 0; i < devices.size(); i++) {
-        if (!audio_is_output_device(devices[i].mType)) {
-            ALOGE("setUidDeviceAffinities() device=%08x is NOT an output device",
-                    devices[i].mType);
-            return BAD_VALUE;
-        }
+    if (!areAllDevicesSupported(devices, audio_is_output_device, __func__)) {
+        return BAD_VALUE;
     }
     status_t res =  mPolicyMixes.setUidDeviceAffinities(uid, devices);
-    if (res == NO_ERROR) {
-        // reevaluate outputs for all given devices
-        for (size_t i = 0; i < devices.size(); i++) {
-            sp<DeviceDescriptor> devDesc = mHwModules.getDeviceDescriptor(
-                            devices[i].mType, devices[i].mAddress.c_str(), String8(),
-                            AUDIO_FORMAT_DEFAULT);
-            SortedVector<audio_io_handle_t> outputs;
-            if (checkOutputsForDevice(devDesc, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
-                    outputs) != NO_ERROR) {
-                ALOGE("setUidDeviceAffinities() error in checkOutputsForDevice for device=%08x"
-                        " addr=%s", devices[i].mType, devices[i].mAddress.c_str());
-                return INVALID_OPERATION;
-            }
-        }
+    if (res != NO_ERROR) {
+        ALOGE("%s() Could not set all device affinities for uid = %d", __FUNCTION__, uid);
+        return res;
     }
-    return res;
+
+    checkForDeviceAndOutputChanges();
+    updateCallAndOutputRouting();
+
+    return NO_ERROR;
 }
 
 status_t AudioPolicyManager::removeUidDeviceAffinities(uid_t uid) {
     ALOGV("%s() uid=%d", __FUNCTION__, uid);
     status_t res = mPolicyMixes.removeUidDeviceAffinities(uid);
     if (res != NO_ERROR) {
-        ALOGE("%s() Could not remove all device affinities fo uid = %d",
+        ALOGE("%s() Could not remove all device affinities for uid = %d",
             __FUNCTION__, uid);
         return INVALID_OPERATION;
     }
 
+    checkForDeviceAndOutputChanges();
+    updateCallAndOutputRouting();
+
     return res;
 }
 
 status_t AudioPolicyManager::setPreferredDeviceForStrategy(product_strategy_t strategy,
                                                    const AudioDeviceTypeAddr &device) {
-    ALOGI("%s() strategy=%d device=%08x addr=%s", __FUNCTION__,
+    ALOGV("%s() strategy=%d device=%08x addr=%s", __FUNCTION__,
             strategy, device.mType, device.mAddress.c_str());
-    // strategy preferred device is only for output devices
-    if (!audio_is_output_device(device.mType)) {
-        ALOGE("%s() device=%08x is NOT an output device", __FUNCTION__, device.mType);
+
+    Vector<AudioDeviceTypeAddr> devices;
+    devices.add(device);
+    if (!areAllDevicesSupported(devices, audio_is_output_device, __func__)) {
         return BAD_VALUE;
     }
-
     status_t status = mEngine->setPreferredDeviceForStrategy(strategy, device);
     if (status != NO_ERROR) {
         ALOGW("Engine could not set preferred device %08x %s for strategy %d",
@@ -3124,17 +3184,10 @@
 
 status_t AudioPolicyManager::setUserIdDeviceAffinities(int userId,
         const Vector<AudioDeviceTypeAddr>& devices) {
-    ALOGI("%s() userId=%d num devices %zu", __FUNCTION__, userId, devices.size());
-    // userId/device affinity is only for output devices
-    for (size_t i = 0; i < devices.size(); i++) {
-        if (!audio_is_output_device(devices[i].mType)) {
-            ALOGE("%s() device=%08x is NOT an output device",
-                    __FUNCTION__,
-                    devices[i].mType);
-            return BAD_VALUE;
-        }
+    ALOGI("%s() userId=%d num devices %zu", __FUNCTION__, userId, devices.size());\
+    if (!areAllDevicesSupported(devices, audio_is_output_device, __func__)) {
+        return BAD_VALUE;
     }
-
     status_t status =  mPolicyMixes.setUserIdDeviceAffinities(userId, devices);
     if (status != NO_ERROR) {
         ALOGE("%s() could not set device affinity for userId %d",
@@ -3641,12 +3694,11 @@
                         audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
                         audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
                         bool isRequestedDeviceForExclusiveUse = false;
-                        std::vector<sp<SwAudioOutputDescriptor>> secondaryOutputs;
                         output_type_t outputType;
                         getOutputForAttrInt(&resultAttr, &output, AUDIO_SESSION_NONE, &attributes,
                                             &stream, sourceDesc->uid(), &config, &flags,
                                             &selectedDeviceId, &isRequestedDeviceForExclusiveUse,
-                                            &secondaryOutputs, &outputType);
+                                            nullptr, &outputType);
                         if (output == AUDIO_IO_HANDLE_NONE) {
                             ALOGV("%s no output for device %s",
                                   __FUNCTION__, sinkDevice->toString().c_str());
@@ -4551,9 +4603,6 @@
                 mTtsOutputAvailable = true;
             }
 
-            if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
-                continue;
-            }
             const DeviceVector &supportedDevices = outProfile->getSupportedDevices();
             DeviceVector availProfileDevices = supportedDevices.filter(mOutputDevicesAll);
             sp<DeviceDescriptor> supportedDevice = 0;
@@ -4594,12 +4643,16 @@
                     outProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
                 mPrimaryOutput = outputDesc;
             }
-            addOutput(output, outputDesc);
-            setOutputDevices(outputDesc,
-                             DeviceVector(supportedDevice),
-                             true,
-                             0,
-                             NULL);
+            if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
+                outputDesc->close();
+            } else {
+                addOutput(output, outputDesc);
+                setOutputDevices(outputDesc,
+                                 DeviceVector(supportedDevice),
+                                 true,
+                                 0,
+                                 NULL);
+            }
         }
         // open input streams needed to access attached devices to validate
         // mAvailableInputDevices list
@@ -4785,7 +4838,7 @@
 
                 if (output != AUDIO_IO_HANDLE_NONE) {
                     addOutput(output, desc);
-                    if (device_distinguishes_on_address(deviceType) && address != "0") {
+                    if (audio_is_remote_submix_device(deviceType) && address != "0") {
                         sp<AudioPolicyMix> policyMix;
                         if (mPolicyMixes.getAudioPolicyMix(deviceType, address, policyMix)
                                 == NO_ERROR) {
@@ -5275,10 +5328,19 @@
     for (size_t i = 0; i < mOutputs.size(); i++) {
         const sp<SwAudioOutputDescriptor>& outputDescriptor = mOutputs[i];
         for (const sp<TrackClientDescriptor>& client : outputDescriptor->getClientIterable()) {
-            sp<SwAudioOutputDescriptor> desc;
-            std::vector<sp<SwAudioOutputDescriptor>> secondaryDescs;
+            sp<AudioPolicyMix> primaryMix;
+            std::vector<sp<AudioPolicyMix>> secondaryMixes;
             status_t status = mPolicyMixes.getOutputForAttr(client->attributes(), client->uid(),
-                                                            client->flags(), desc, &secondaryDescs);
+                    client->flags(), primaryMix, &secondaryMixes);
+            std::vector<sp<SwAudioOutputDescriptor>> secondaryDescs;
+            for (auto &secondaryMix : secondaryMixes) {
+                sp<SwAudioOutputDescriptor> outputDesc = secondaryMix->getOutput();
+                if (outputDesc != nullptr &&
+                    outputDesc->mIoHandle != AUDIO_IO_HANDLE_NONE) {
+                    secondaryDescs.push_back(outputDesc);
+                }
+            }
+
             if (status != OK ||
                 !std::equal(client->getSecondaryOutputs().begin(),
                             client->getSecondaryOutputs().end(),
@@ -5482,21 +5544,17 @@
     }
     // check dynamic policies but only for primary descriptors (secondary not used for audible
     // audio routing, only used for duplication for playback capture)
-    sp<SwAudioOutputDescriptor> policyDesc;
+    sp<AudioPolicyMix> policyMix;
     status_t status = mPolicyMixes.getOutputForAttr(attr, 0 /*uid unknown here*/,
-            AUDIO_OUTPUT_FLAG_NONE, policyDesc, nullptr);
+            AUDIO_OUTPUT_FLAG_NONE, policyMix, nullptr);
     if (status != OK) {
         return status;
     }
-    if (policyDesc != nullptr) {
-        sp<AudioPolicyMix> mix = policyDesc->mPolicyMix.promote();
-        if (mix != nullptr) {
-            AudioDeviceTypeAddr device(mix->mDeviceType, mix->mDeviceAddress.c_str());
-            devices->push_back(device);
-            return NO_ERROR;
-        }
+    if (policyMix != nullptr && policyMix->getOutput() != nullptr) {
+        AudioDeviceTypeAddr device(policyMix->mDeviceType, policyMix->mDeviceAddress.c_str());
+        devices->push_back(device);
+        return NO_ERROR;
     }
-
     DeviceVector curDevices = mEngine->getOutputDevicesForAttributes(attr, nullptr, false);
     for (const auto& device : curDevices) {
         devices->push_back(device->getDeviceTypeAddr());
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index c142880..b588f89 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -837,7 +837,7 @@
                 audio_output_flags_t *flags,
                 audio_port_handle_t *selectedDeviceId,
                 bool *isRequestedDeviceForExclusiveUse,
-                std::vector<sp<SwAudioOutputDescriptor>> *secondaryDescs,
+                std::vector<sp<AudioPolicyMix>> *secondaryMixes,
                 output_type_t *outputType);
         // internal method to return the output handle for the given device and format
         audio_io_handle_t getOutputForDevices(
@@ -848,6 +848,16 @@
                 audio_output_flags_t *flags,
                 bool forceMutingHaptic = false);
 
+        // Internal method checking if a direct output can be opened matching the requested
+        // attributes, flags, config and devices.
+        // If NAME_NOT_FOUND is returned, an attempt can be made to open a mixed output.
+        status_t openDirectOutput(
+                audio_stream_type_t stream,
+                audio_session_t session,
+                const audio_config_t *config,
+                audio_output_flags_t flags,
+                const DeviceVector &devices,
+                audio_io_handle_t *output);
         /**
          * @brief getInputForDevice selects an input handle for a given input device and
          * requester context
@@ -926,6 +936,12 @@
                 int delayMs,
                 uid_t uid,
                 sp<AudioPatch> *patchDescPtr);
+
+        bool areAllDevicesSupported(
+                const Vector<AudioDeviceTypeAddr>& devices,
+                std::function<bool(audio_devices_t)> predicate,
+                const char* context);
+
 };
 
 };
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index d743be9..a15970a 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -676,6 +676,7 @@
         case AUDIO_SOURCE_VOICE_CALL:
         case AUDIO_SOURCE_REMOTE_SUBMIX:
         case AUDIO_SOURCE_FM_TUNER:
+        case AUDIO_SOURCE_ECHO_REFERENCE:
             return true;
         default:
             break;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 2d46122..b00a2d9 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -2344,6 +2344,21 @@
     }
 }
 
+bool Camera3Device::checkAbandonedStreamsLocked() {
+    if ((mInputStream.get() != nullptr) && (mInputStream->isAbandoned())) {
+        return true;
+    }
+
+    for (size_t i = 0; i < mOutputStreams.size(); i++) {
+        auto stream = mOutputStreams[i];
+        if ((stream.get() != nullptr) && (stream->isAbandoned())) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
 bool Camera3Device::reconfigureCamera(const CameraMetadata& sessionParams) {
     ATRACE_CALL();
     bool ret = false;
@@ -2352,6 +2367,12 @@
     nsecs_t maxExpectedDuration = getExpectedInFlightDuration();
 
     Mutex::Autolock l(mLock);
+    if (checkAbandonedStreamsLocked()) {
+        ALOGW("%s: Abandoned stream detected, session parameters can't be applied correctly!",
+                __FUNCTION__);
+        return true;
+    }
+
     auto rc = internalPauseAndWaitLocked(maxExpectedDuration);
     if (rc == NO_ERROR) {
         mNeedConfig = true;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index b373a64..19ecf4b 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -648,6 +648,12 @@
     bool reconfigureCamera(const CameraMetadata& sessionParams);
 
     /**
+     * Return true in case of any output or input abandoned streams,
+     * otherwise return false.
+     */
+    bool checkAbandonedStreamsLocked();
+
+    /**
      * Filter stream session parameters and configure camera HAL.
      */
     status_t filterParamsAndConfigureLocked(const CameraMetadata& sessionParams,
diff --git a/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp b/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
index 84da45a..a87de77 100644
--- a/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
+++ b/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
@@ -243,10 +243,15 @@
             if (weight == 0) {
                 continue;
             }
-            // Top-left is inclusively clamped
-            scaleCoordinates(entry.data.i32 + j, 1, zoomRatio, ClampInclusive);
-            // Bottom-right is exclusively clamped
-            scaleCoordinates(entry.data.i32 + j + 2, 1, zoomRatio, ClampExclusive);
+            // Top left (inclusive)
+            scaleCoordinates(entry.data.i32 + j, 1, zoomRatio, true /*clamp*/);
+            // Bottom right (exclusive): Use adjacent inclusive pixel to
+            // calculate.
+            entry.data.i32[j+2] -= 1;
+            entry.data.i32[j+3] -= 1;
+            scaleCoordinates(entry.data.i32 + j + 2, 1, zoomRatio, true /*clamp*/);
+            entry.data.i32[j+2] += 1;
+            entry.data.i32[j+3] += 1;
         }
     }
 
@@ -258,7 +263,7 @@
     if (isResult) {
         for (auto pts : kResultPointsToCorrectNoClamp) {
             entry = metadata->find(pts);
-            scaleCoordinates(entry.data.i32, entry.count / 2, zoomRatio, ClampOff);
+            scaleCoordinates(entry.data.i32, entry.count / 2, zoomRatio, false /*clamp*/);
         }
     }
 
@@ -282,10 +287,15 @@
             if (weight == 0) {
                 continue;
             }
-            // Top-left is inclusively clamped
-            scaleCoordinates(entry.data.i32 + j, 1, 1.0 / zoomRatio, ClampInclusive);
-            // Bottom-right is exclusively clamped
-            scaleCoordinates(entry.data.i32 + j + 2, 1, 1.0 / zoomRatio, ClampExclusive);
+            // Top-left (inclusive)
+            scaleCoordinates(entry.data.i32 + j, 1, 1.0 / zoomRatio, true /*clamp*/);
+            // Bottom-right (exclusive): Use adjacent inclusive pixel to
+            // calculate.
+            entry.data.i32[j+2] -= 1;
+            entry.data.i32[j+3] -= 1;
+            scaleCoordinates(entry.data.i32 + j + 2, 1, 1.0 / zoomRatio, true /*clamp*/);
+            entry.data.i32[j+2] += 1;
+            entry.data.i32[j+3] += 1;
         }
     }
     for (auto rect : kRectsToCorrect) {
@@ -295,7 +305,7 @@
     if (isResult) {
         for (auto pts : kResultPointsToCorrectNoClamp) {
             entry = metadata->find(pts);
-            scaleCoordinates(entry.data.i32, entry.count / 2, 1.0 / zoomRatio, ClampOff);
+            scaleCoordinates(entry.data.i32, entry.count / 2, 1.0 / zoomRatio, false /*clamp*/);
         }
     }
 
@@ -309,28 +319,31 @@
 }
 
 void ZoomRatioMapper::scaleCoordinates(int32_t* coordPairs, int coordCount,
-        float scaleRatio, ClampMode clamp) {
+        float scaleRatio, bool clamp) {
+    // A pixel's coordinate is represented by the position of its top-left corner.
+    // To avoid the rounding error, we use the coordinate for the center of the
+    // pixel instead:
+    // 1. First shift the coordinate system half pixel both horizontally and
+    // vertically, so that [x, y] is the center of the pixel, not the top-left corner.
+    // 2. Do zoom operation to scale the coordinate relative to the center of
+    // the active array (shifted by 0.5 pixel as well).
+    // 3. Shift the coordinate system back by directly using the pixel center
+    // coordinate.
     for (int i = 0; i < coordCount * 2; i += 2) {
         float x = coordPairs[i];
         float y = coordPairs[i + 1];
-        float xCentered = x - mArrayWidth / 2;
-        float yCentered = y - mArrayHeight / 2;
+        float xCentered = x - (mArrayWidth - 2) / 2;
+        float yCentered = y - (mArrayHeight - 2) / 2;
         float scaledX = xCentered * scaleRatio;
         float scaledY = yCentered * scaleRatio;
-        scaledX += mArrayWidth / 2;
-        scaledY += mArrayHeight / 2;
+        scaledX += (mArrayWidth - 2) / 2;
+        scaledY += (mArrayHeight - 2) / 2;
+        coordPairs[i] = static_cast<int32_t>(std::round(scaledX));
+        coordPairs[i+1] = static_cast<int32_t>(std::round(scaledY));
         // Clamp to within activeArray/preCorrectionActiveArray
-        coordPairs[i] = static_cast<int32_t>(scaledX);
-        coordPairs[i+1] = static_cast<int32_t>(scaledY);
-        if (clamp != ClampOff) {
-            int32_t right, bottom;
-            if (clamp == ClampInclusive) {
-                right = mArrayWidth - 1;
-                bottom = mArrayHeight - 1;
-            } else {
-                right = mArrayWidth;
-                bottom = mArrayHeight;
-            }
+        if (clamp) {
+            int32_t right = mArrayWidth - 1;
+            int32_t bottom = mArrayHeight - 1;
             coordPairs[i] =
                     std::min(right, std::max(0, coordPairs[i]));
             coordPairs[i+1] =
@@ -343,25 +356,25 @@
 void ZoomRatioMapper::scaleRects(int32_t* rects, int rectCount,
         float scaleRatio) {
     for (int i = 0; i < rectCount * 4; i += 4) {
-        // Map from (l, t, width, height) to (l, t, r, b).
-        // [l, t] is inclusive, and [r, b] is exclusive.
+        // Map from (l, t, width, height) to (l, t, l+width-1, t+height-1),
+        // where both top-left and bottom-right are inclusive.
         int32_t coords[4] = {
             rects[i],
             rects[i + 1],
-            rects[i] + rects[i + 2],
-            rects[i + 1] + rects[i + 3]
+            rects[i] + rects[i + 2] - 1,
+            rects[i + 1] + rects[i + 3] - 1
         };
 
         // top-left
-        scaleCoordinates(coords, 1, scaleRatio, ClampInclusive);
+        scaleCoordinates(coords, 1, scaleRatio, true /*clamp*/);
         // bottom-right
-        scaleCoordinates(coords+2, 1, scaleRatio, ClampExclusive);
+        scaleCoordinates(coords+2, 1, scaleRatio, true /*clamp*/);
 
         // Map back to (l, t, width, height)
         rects[i] = coords[0];
         rects[i + 1] = coords[1];
-        rects[i + 2] = coords[2] - coords[0];
-        rects[i + 3] = coords[3] - coords[1];
+        rects[i + 2] = coords[2] - coords[0] + 1;
+        rects[i + 3] = coords[3] - coords[1] + 1;
     }
 }
 
diff --git a/services/camera/libcameraservice/device3/ZoomRatioMapper.h b/services/camera/libcameraservice/device3/ZoomRatioMapper.h
index aa3d913..698f87f 100644
--- a/services/camera/libcameraservice/device3/ZoomRatioMapper.h
+++ b/services/camera/libcameraservice/device3/ZoomRatioMapper.h
@@ -65,14 +65,8 @@
     status_t updateCaptureResult(CameraMetadata *request, bool requestedZoomRatioIs1);
 
   public: // Visible for testing. Do not use concurently.
-    enum ClampMode {
-        ClampOff,
-        ClampInclusive,
-        ClampExclusive,
-    };
-
     void scaleCoordinates(int32_t* coordPairs, int coordCount,
-            float scaleRatio, ClampMode clamp);
+            float scaleRatio, bool clamp);
 
     bool isValid() { return mIsValid; }
   private:
diff --git a/services/camera/libcameraservice/tests/ZoomRatioTest.cpp b/services/camera/libcameraservice/tests/ZoomRatioTest.cpp
index 300da09..4e94991 100644
--- a/services/camera/libcameraservice/tests/ZoomRatioTest.cpp
+++ b/services/camera/libcameraservice/tests/ZoomRatioTest.cpp
@@ -171,35 +171,35 @@
 
     std::array<int32_t, 16> originalCoords = {
             0, 0, // top-left
-            width, 0, // top-right
-            0, height, // bottom-left
-            width, height, // bottom-right
-            width / 2, height / 2, // center
-            width / 4, height / 4, // top-left after 2x
-            width / 3, height * 2 / 3, // bottom-left after 3x zoom
-            width * 7 / 8, height / 2, // middle-right after 1.33x zoom
+            width - 1, 0, // top-right
+            0, height - 1, // bottom-left
+            width - 1, height - 1, // bottom-right
+            (width - 1) / 2, (height - 1) / 2, // center
+            (width - 1) / 4, (height - 1) / 4, // top-left after 2x
+            (width - 1) / 3, (height - 1) * 2 / 3, // bottom-left after 3x zoom
+            (width - 1) * 7 / 8, (height - 1) / 2, // middle-right after 1.33x zoom
     };
 
     // Verify 1.0x zoom doesn't change the coordinates
     auto coords = originalCoords;
-    mapper.scaleCoordinates(coords.data(), coords.size()/2, 1.0f, ZoomRatioMapper::ClampOff);
+    mapper.scaleCoordinates(coords.data(), coords.size()/2, 1.0f, false /*clamp*/);
     for (size_t i = 0; i < coords.size(); i++) {
         EXPECT_EQ(coords[i], originalCoords[i]);
     }
 
     // Verify 2.0x zoom work as expected (no clamping)
     std::array<float, 16> expected2xCoords = {
-            - width / 2.0f, - height / 2.0f,// top-left
-            width * 3 / 2.0f, - height / 2.0f, // top-right
-            - width / 2.0f, height * 3 / 2.0f, // bottom-left
-            width * 3 / 2.0f, height * 3 / 2.0f, // bottom-right
-            width / 2.0f, height / 2.0f, // center
+            - (width - 1) / 2.0f, - (height - 1) / 2.0f,// top-left
+            (width - 1) * 3 / 2.0f, - (height - 1) / 2.0f, // top-right
+            - (width - 1) / 2.0f, (height - 1) * 3 / 2.0f, // bottom-left
+            (width - 1) * 3 / 2.0f, (height - 1) * 3 / 2.0f, // bottom-right
+            (width - 1) / 2.0f, (height - 1) / 2.0f, // center
             0, 0, // top-left after 2x
-            width / 6.0f, height - height / 6.0f, // bottom-left after 3x zoom
-            width + width / 4.0f, height / 2.0f, // middle-right after 1.33x zoom
+            (width - 1) / 6.0f, (height - 1) * 5.0f / 6.0f, // bottom-left after 3x zoom
+            (width - 1) * 5.0f / 4.0f, (height - 1) / 2.0f, // middle-right after 1.33x zoom
     };
     coords = originalCoords;
-    mapper.scaleCoordinates(coords.data(), coords.size()/2, 2.0f, ZoomRatioMapper::ClampOff);
+    mapper.scaleCoordinates(coords.data(), coords.size()/2, 2.0f, false /*clamp*/);
     for (size_t i = 0; i < coords.size(); i++) {
         EXPECT_LE(std::abs(coords[i] - expected2xCoords[i]), kMaxAllowedPixelError);
     }
@@ -207,16 +207,16 @@
     // Verify 2.0x zoom work as expected (with inclusive clamping)
     std::array<float, 16> expected2xCoordsClampedInc = {
             0, 0, // top-left
-            static_cast<float>(width) - 1, 0, // top-right
-            0, static_cast<float>(height) - 1, // bottom-left
-            static_cast<float>(width) - 1, static_cast<float>(height) - 1, // bottom-right
-            width / 2.0f, height / 2.0f, // center
+            width - 1.0f, 0, // top-right
+            0, height - 1.0f, // bottom-left
+            width - 1.0f, height - 1.0f, // bottom-right
+            (width - 1) / 2.0f, (height - 1) / 2.0f, // center
             0, 0, // top-left after 2x
-            width / 6.0f, height - height / 6.0f , // bottom-left after 3x zoom
-            static_cast<float>(width) - 1,  height / 2.0f, // middle-right after 1.33x zoom
+            (width - 1) / 6.0f, (height - 1) * 5.0f / 6.0f , // bottom-left after 3x zoom
+            width - 1.0f,  (height - 1) / 2.0f, // middle-right after 1.33x zoom
     };
     coords = originalCoords;
-    mapper.scaleCoordinates(coords.data(), coords.size()/2, 2.0f, ZoomRatioMapper::ClampInclusive);
+    mapper.scaleCoordinates(coords.data(), coords.size()/2, 2.0f, true /*clamp*/);
     for (size_t i = 0; i < coords.size(); i++) {
         EXPECT_LE(std::abs(coords[i] - expected2xCoordsClampedInc[i]), kMaxAllowedPixelError);
     }
@@ -224,33 +224,33 @@
     // Verify 2.0x zoom work as expected (with exclusive clamping)
     std::array<float, 16> expected2xCoordsClampedExc = {
             0, 0, // top-left
-            static_cast<float>(width), 0, // top-right
-            0, static_cast<float>(height), // bottom-left
-            static_cast<float>(width), static_cast<float>(height), // bottom-right
+            width - 1.0f, 0, // top-right
+            0, height - 1.0f, // bottom-left
+            width - 1.0f, height - 1.0f, // bottom-right
             width / 2.0f, height / 2.0f, // center
             0, 0, // top-left after 2x
-            width / 6.0f, height - height / 6.0f , // bottom-left after 3x zoom
-            static_cast<float>(width),  height / 2.0f, // middle-right after 1.33x zoom
+            (width - 1) / 6.0f, (height - 1) * 5.0f / 6.0f , // bottom-left after 3x zoom
+            width - 1.0f,  height / 2.0f, // middle-right after 1.33x zoom
     };
     coords = originalCoords;
-    mapper.scaleCoordinates(coords.data(), coords.size()/2, 2.0f, ZoomRatioMapper::ClampExclusive);
+    mapper.scaleCoordinates(coords.data(), coords.size()/2, 2.0f, true /*clamp*/);
     for (size_t i = 0; i < coords.size(); i++) {
         EXPECT_LE(std::abs(coords[i] - expected2xCoordsClampedExc[i]), kMaxAllowedPixelError);
     }
 
     // Verify 0.33x zoom work as expected
     std::array<float, 16> expectedZoomOutCoords = {
-            width / 3.0f, height / 3.0f, // top-left
-            width * 2 / 3.0f, height / 3.0f, // top-right
-            width / 3.0f, height * 2 / 3.0f, // bottom-left
-            width * 2 / 3.0f, height * 2 / 3.0f, // bottom-right
-            width / 2.0f, height / 2.0f, // center
-            width * 5 / 12.0f, height * 5 / 12.0f, // top-left after 2x
-            width * 4 / 9.0f, height * 5 / 9.0f, // bottom-left after 3x zoom-in
-            width * 5 / 8.0f, height / 2.0f, // middle-right after 1.33x zoom-in
+            (width - 1) / 3.0f, (height - 1) / 3.0f, // top-left
+            (width - 1) * 2 / 3.0f, (height - 1) / 3.0f, // top-right
+            (width - 1) / 3.0f, (height - 1) * 2 / 3.0f, // bottom-left
+            (width - 1) * 2 / 3.0f, (height - 1) * 2 / 3.0f, // bottom-right
+            (width - 1) / 2.0f, (height - 1) / 2.0f, // center
+            (width - 1) * 5 / 12.0f, (height - 1) * 5 / 12.0f, // top-left after 2x
+            (width - 1) * 4 / 9.0f, (height - 1) * 5 / 9.0f, // bottom-left after 3x zoom-in
+            (width - 1) * 5 / 8.0f, (height - 1) / 2.0f, // middle-right after 1.33x zoom-in
     };
     coords = originalCoords;
-    mapper.scaleCoordinates(coords.data(), coords.size()/2, 1.0f/3, ZoomRatioMapper::ClampOff);
+    mapper.scaleCoordinates(coords.data(), coords.size()/2, 1.0f/3, false /*clamp*/);
     for (size_t i = 0; i < coords.size(); i++) {
         EXPECT_LE(std::abs(coords[i] - expectedZoomOutCoords[i]), kMaxAllowedPixelError);
     }
@@ -323,7 +323,8 @@
     entry = metadata.find(ANDROID_SCALER_CROP_REGION);
     ASSERT_EQ(entry.count, 4U);
     for (int i = 0; i < 4; i++) {
-        EXPECT_EQ(entry.data.i32[i], testDefaultCropSize[index][i]);
+        EXPECT_LE(std::abs(entry.data.i32[i] - testDefaultCropSize[index][i]),
+                kMaxAllowedPixelError);
     }
     entry = metadata.find(ANDROID_CONTROL_ZOOM_RATIO);
     EXPECT_NEAR(entry.data.f[0], 2.0f, kMaxAllowedRatioError);
@@ -335,7 +336,7 @@
     entry = metadata.find(ANDROID_SCALER_CROP_REGION);
     ASSERT_EQ(entry.count, 4U);
     for (int i = 0; i < 4; i++) {
-        EXPECT_EQ(entry.data.i32[i], test2xCropRegion[index][i]);
+        EXPECT_LE(std::abs(entry.data.i32[i] - test2xCropRegion[index][i]), kMaxAllowedPixelError);
     }
 
     // Letter boxing crop region, zoomRatio is 1.0
diff --git a/services/mediametrics/TimeMachine.h b/services/mediametrics/TimeMachine.h
index 6861c78..c82778b 100644
--- a/services/mediametrics/TimeMachine.h
+++ b/services/mediametrics/TimeMachine.h
@@ -75,21 +75,30 @@
     class KeyHistory  {
     public:
         template <typename T>
-        KeyHistory(T key, pid_t pid, uid_t uid, int64_t time)
+        KeyHistory(T key, uid_t allowUid, int64_t time)
             : mKey(key)
-            , mPid(pid)
-            , mUid(uid)
+            , mAllowUid(allowUid)
             , mCreationTime(time)
             , mLastModificationTime(time)
         {
-            putValue(BUNDLE_PID, (int32_t)pid, time);
-            putValue(BUNDLE_UID, (int32_t)uid, time);
+            // allowUid allows an untrusted client with a matching uid to set properties
+            // in this key.
+            // If allowUid == (uid_t)-1, no untrusted client may set properties in the key.
+            if (allowUid != (uid_t)-1) {
+                // Set ALLOWUID property here; does not change after key creation.
+                putValue(AMEDIAMETRICS_PROP_ALLOWUID, (int32_t)allowUid, time);
+            }
         }
 
         KeyHistory(const KeyHistory &other) = default;
 
+        // Return NO_ERROR only if the passed in uidCheck is -1 or matches
+        // the internal mAllowUid.
+        // An external submit will always have a valid uidCheck parameter.
+        // An internal get request within mediametrics will have a uidCheck == -1 which
+        // we allow to proceed.
         status_t checkPermission(uid_t uidCheck) const {
-            return uidCheck != (uid_t)-1 && uidCheck != mUid ? PERMISSION_DENIED : NO_ERROR;
+            return uidCheck != (uid_t)-1 && uidCheck != mAllowUid ? PERMISSION_DENIED : NO_ERROR;
         }
 
         template <typename T>
@@ -199,8 +208,7 @@
         }
 
         const std::string mKey;
-        const pid_t mPid __unused;
-        const uid_t mUid;
+        const uid_t mAllowUid;
         const int64_t mCreationTime __unused;
 
         int64_t mLastModificationTime;
@@ -276,10 +284,13 @@
 
                 (void)gc(garbage);
 
+                // We set the allowUid for client access on key creation.
+                int32_t allowUid = -1;
+                (void)item->get(AMEDIAMETRICS_PROP_ALLOWUID, &allowUid);
                 // no keylock needed here as we are sole owner
                 // until placed on mHistory.
                 keyHistory = std::make_shared<KeyHistory>(
-                    key, item->getPid(), item->getUid(), time);
+                    key, allowUid, time);
                 mHistory[key] = keyHistory;
             } else {
                 keyHistory = it->second;
diff --git a/services/mediametrics/tests/mediametrics_tests.cpp b/services/mediametrics/tests/mediametrics_tests.cpp
index 78eb71c..cf0dceb 100644
--- a/services/mediametrics/tests/mediametrics_tests.cpp
+++ b/services/mediametrics/tests/mediametrics_tests.cpp
@@ -813,6 +813,42 @@
   ASSERT_LT(9, audioAnalytics.dump(1000).second /* lines */);
 }
 
+TEST(mediametrics_tests, audio_analytics_permission2) {
+  constexpr int32_t transactionUid = 1010; // arbitrary
+  auto item = std::make_shared<mediametrics::Item>("audio.1");
+  (*item).set("one", (int32_t)1)
+         .set("two", (int32_t)2)
+         .set(AMEDIAMETRICS_PROP_ALLOWUID, transactionUid)
+         .setTimestamp(10);
+
+  // item2 submitted untrusted
+  auto item2 = std::make_shared<mediametrics::Item>("audio.1");
+  (*item2).set("three", (int32_t)3)
+         .setUid(transactionUid)
+         .setTimestamp(11);
+
+  auto item3 = std::make_shared<mediametrics::Item>("audio.2");
+  (*item3).set("four", (int32_t)4)
+          .setTimestamp(12);
+
+  android::mediametrics::AudioAnalytics audioAnalytics;
+
+  // untrusted entities cannot create a new key.
+  ASSERT_EQ(PERMISSION_DENIED, audioAnalytics.submit(item, false /* isTrusted */));
+  ASSERT_EQ(PERMISSION_DENIED, audioAnalytics.submit(item2, false /* isTrusted */));
+
+  // TODO: Verify contents of AudioAnalytics.
+  // Currently there is no getter API in AudioAnalytics besides dump.
+  ASSERT_EQ(9, audioAnalytics.dump(1000).second /* lines */);
+
+  ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item, true /* isTrusted */));
+  // untrusted entities can add to an existing key
+  ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item2, false /* isTrusted */));
+
+  // Check that we have some info in the dump.
+  ASSERT_LT(9, audioAnalytics.dump(1000).second /* lines */);
+}
+
 TEST(mediametrics_tests, audio_analytics_dump) {
   auto item = std::make_shared<mediametrics::Item>("audio.1");
   (*item).set("one", (int32_t)1)
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index be5af00..ff45c87 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -114,6 +114,7 @@
         info.uid = uid;
         info.clientId = clientId;
         info.client = client;
+        info.pendingRemoval = false;
 
         index = infos.add(clientId, info);
     }
@@ -648,6 +649,36 @@
     return Status::ok();
 }
 
+Status ResourceManagerService::markClientForPendingRemoval(int32_t pid, int64_t clientId) {
+    String8 log = String8::format(
+            "markClientForPendingRemoval(pid %d, clientId %lld)",
+            pid, (long long) clientId);
+    mServiceLog->add(log);
+
+    Mutex::Autolock lock(mLock);
+    if (!mProcessInfo->isValidPid(pid)) {
+        ALOGE("Rejected markClientForPendingRemoval call with invalid pid.");
+        return Status::fromServiceSpecificError(BAD_VALUE);
+    }
+    ssize_t index = mMap.indexOfKey(pid);
+    if (index < 0) {
+        ALOGV("markClientForPendingRemoval: didn't find pid %d for clientId %lld",
+              pid, (long long)clientId);
+        return Status::ok();
+    }
+    ResourceInfos &infos = mMap.editValueAt(index);
+
+    index = infos.indexOfKey(clientId);
+    if (index < 0) {
+        ALOGV("markClientForPendingRemoval: didn't find clientId %lld", (long long) clientId);
+        return Status::ok();
+    }
+
+    ResourceInfo &info = infos.editValueAt(index);
+    info.pendingRemoval = true;
+    return Status::ok();
+}
+
 bool ResourceManagerService::getPriority_l(int pid, int* priority) {
     int newPid = pid;
 
@@ -693,6 +724,12 @@
     int lowestPriorityPid;
     int lowestPriority;
     int callingPriority;
+
+    // Before looking into other processes, check if we have clients marked for
+    // pending removal in the same process.
+    if (getBiggestClient_l(callingPid, type, client, true /* pendingRemovalOnly */)) {
+        return true;
+    }
     if (!getPriority_l(callingPid, &callingPriority)) {
         ALOGE("getLowestPriorityBiggestClient_l: can't get process priority for pid %d",
                 callingPid);
@@ -761,7 +798,8 @@
 }
 
 bool ResourceManagerService::getBiggestClient_l(
-        int pid, MediaResource::Type type, std::shared_ptr<IResourceManagerClient> *client) {
+        int pid, MediaResource::Type type, std::shared_ptr<IResourceManagerClient> *client,
+        bool pendingRemovalOnly) {
     ssize_t index = mMap.indexOfKey(pid);
     if (index < 0) {
         ALOGE("getBiggestClient_l: can't find resource info for pid %d", pid);
@@ -773,6 +811,9 @@
     const ResourceInfos &infos = mMap.valueAt(index);
     for (size_t i = 0; i < infos.size(); ++i) {
         const ResourceList &resources = infos[i].resources;
+        if (pendingRemovalOnly && !infos[i].pendingRemoval) {
+            continue;
+        }
         for (auto it = resources.begin(); it != resources.end(); it++) {
             const MediaResourceParcel &resource = it->second;
             if (resource.type == type) {
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index f500c62..ee982b7 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -18,6 +18,8 @@
 #ifndef ANDROID_MEDIA_RESOURCEMANAGERSERVICE_H
 #define ANDROID_MEDIA_RESOURCEMANAGERSERVICE_H
 
+#include <map>
+
 #include <aidl/android/media/BnResourceManagerService.h>
 #include <arpa/inet.h>
 #include <media/MediaResource.h>
@@ -50,6 +52,7 @@
     std::shared_ptr<IResourceManagerClient> client;
     sp<DeathNotifier> deathNotifier;
     ResourceList resources;
+    bool pendingRemoval{false};
 };
 
 // TODO: convert these to std::map
@@ -122,6 +125,8 @@
             int originalPid,
             int newPid) override;
 
+    Status markClientForPendingRemoval(int32_t pid, int64_t clientId) override;
+
     Status removeResource(int pid, int64_t clientId, bool checkValid);
 
 private:
@@ -146,7 +151,8 @@
     // Gets the client who owns biggest piece of specified resource type from pid.
     // Returns false if failed. The client will remain unchanged if failed.
     bool getBiggestClient_l(int pid, MediaResource::Type type,
-            std::shared_ptr<IResourceManagerClient> *client);
+            std::shared_ptr<IResourceManagerClient> *client,
+            bool pendingRemovalOnly = false);
 
     bool isCallingPriorityHigher_l(int callingPid, int pid);
 
diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
index 5d839fa..702935d 100644
--- a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
@@ -472,6 +472,56 @@
         }
     }
 
+    void testMarkClientForPendingRemoval() {
+        bool result;
+
+        {
+            addResource();
+            mService->mSupportsSecureWithNonSecureCodec = true;
+
+            std::vector<MediaResourceParcel> resources;
+            resources.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
+
+            // Remove low priority clients
+            mService->removeClient(kTestPid1, getId(mTestClient1));
+
+            // no lower priority client
+            CHECK_STATUS_FALSE(mService->reclaimResource(kTestPid2, resources, &result));
+            verifyClients(false /* c1 */, false /* c2 */, false /* c3 */);
+
+            mService->markClientForPendingRemoval(kTestPid2, getId(mTestClient2));
+
+            // client marked for pending removal from the same process got reclaimed
+            CHECK_STATUS_TRUE(mService->reclaimResource(kTestPid2, resources, &result));
+            verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
+
+            // clean up client 3 which still left
+            mService->removeClient(kTestPid2, getId(mTestClient3));
+        }
+
+        {
+            addResource();
+            mService->mSupportsSecureWithNonSecureCodec = true;
+
+            std::vector<MediaResourceParcel> resources;
+            resources.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
+
+            mService->markClientForPendingRemoval(kTestPid2, getId(mTestClient2));
+
+            // client marked for pending removal from the same process got reclaimed
+            // first, even though there are lower priority process
+            CHECK_STATUS_TRUE(mService->reclaimResource(kTestPid2, resources, &result));
+            verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
+
+            // lower priority client got reclaimed
+            CHECK_STATUS_TRUE(mService->reclaimResource(kTestPid2, resources, &result));
+            verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
+
+            // clean up client 3 which still left
+            mService->removeClient(kTestPid2, getId(mTestClient3));
+        }
+    }
+
     void testRemoveClient() {
         addResource();
 
@@ -900,4 +950,8 @@
     testOverridePid();
 }
 
+TEST_F(ResourceManagerServiceTest, markClientForPendingRemoval) {
+    testMarkClientForPendingRemoval();
+}
+
 } // namespace android
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index aba8e08..cac7453 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -144,6 +144,9 @@
         pid_t pid = request.getProcessId();
         AAudioClientTracker::getInstance().registerClientStream(pid, serviceStream);
         configurationOutput.copyFrom(*serviceStream);
+        // Log open in MediaMetrics after we have the handle because we need the handle to
+        // create the metrics ID.
+        serviceStream->logOpen(handle);
         return handle;
     }
 }
diff --git a/services/oboeservice/AAudioService.h b/services/oboeservice/AAudioService.h
index eddb5a0..7167868 100644
--- a/services/oboeservice/AAudioService.h
+++ b/services/oboeservice/AAudioService.h
@@ -115,6 +115,7 @@
     // and share them with this code. Look for "kPriorityFastMixer".
     static constexpr int32_t        kRealTimeAudioPriorityClient = 2;
     static constexpr int32_t        kRealTimeAudioPriorityService = 3;
+
 };
 
 } /* namespace android */
diff --git a/services/oboeservice/AAudioServiceEndpoint.h b/services/oboeservice/AAudioServiceEndpoint.h
index a6bb019..ad30087 100644
--- a/services/oboeservice/AAudioServiceEndpoint.h
+++ b/services/oboeservice/AAudioServiceEndpoint.h
@@ -109,6 +109,8 @@
         return mConnected;
     }
 
+    static audio_attributes_t getAudioAttributesFrom(const AAudioStreamParameters *params);
+
 protected:
 
     /**
@@ -119,8 +121,6 @@
 
     void                     disconnectRegisteredStreams();
 
-    static audio_attributes_t getAudioAttributesFrom(const AAudioStreamParameters *params);
-
     mutable std::mutex       mLockStreams;
     std::vector<android::sp<AAudioServiceStreamBase>> mRegisteredStreams;
 
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index 39e90b1..dba9fb9 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -22,8 +22,12 @@
 #include <iostream>
 #include <mutex>
 
+#include <media/MediaMetricsItem.h>
+#include <media/TypeConverter.h>
+
 #include "binding/IAAudioService.h"
 #include "binding/AAudioServiceMessage.h"
+#include "core/AudioGlobal.h"
 #include "utility/AudioClock.h"
 
 #include "AAudioEndpointManager.h"
@@ -51,6 +55,14 @@
 }
 
 AAudioServiceStreamBase::~AAudioServiceStreamBase() {
+    // May not be set if open failed.
+    if (mMetricsId.size() > 0) {
+        mediametrics::LogItem(mMetricsId)
+                .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_DTOR)
+                .set(AMEDIAMETRICS_PROP_STATE, AudioGlobal_convertStreamStateToText(getState()))
+                .record();
+    }
+
     // If the stream is deleted when OPEN or in use then audio resources will leak.
     // This would indicate an internal error. So we want to find this ASAP.
     LOG_ALWAYS_FATAL_IF(!(getState() == AAUDIO_STREAM_STATE_CLOSED
@@ -81,6 +93,36 @@
     return result.str();
 }
 
+void AAudioServiceStreamBase::logOpen(aaudio_handle_t streamHandle) {
+    // This is the first log sent from the AAudio Service for a stream.
+    mMetricsId = std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM)
+            + std::to_string(streamHandle);
+
+    audio_attributes_t attributes = AAudioServiceEndpoint::getAudioAttributesFrom(this);
+
+    // Once this item is logged by the server, the client with the same PID, UID
+    // can also log properties.
+    mediametrics::LogItem(mMetricsId)
+        .setPid(getOwnerProcessId())
+        .setUid(getOwnerUserId())
+        .set(AMEDIAMETRICS_PROP_ALLOWUID, (int32_t)getOwnerUserId())
+        .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_OPEN)
+        // the following are immutable
+        .set(AMEDIAMETRICS_PROP_BUFFERCAPACITYFRAMES, (int32_t)getBufferCapacity())
+        .set(AMEDIAMETRICS_PROP_BURSTFRAMES, (int32_t)getFramesPerBurst())
+        .set(AMEDIAMETRICS_PROP_CHANNELCOUNT, (int32_t)getSamplesPerFrame())
+        .set(AMEDIAMETRICS_PROP_CONTENTTYPE, toString(attributes.content_type).c_str())
+        .set(AMEDIAMETRICS_PROP_DIRECTION,
+                AudioGlobal_convertDirectionToText(getDirection()))
+        .set(AMEDIAMETRICS_PROP_ENCODING, toString(getFormat()).c_str())
+        .set(AMEDIAMETRICS_PROP_ROUTEDDEVICEID, (int32_t)getDeviceId())
+        .set(AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)getSampleRate())
+        .set(AMEDIAMETRICS_PROP_SESSIONID, (int32_t)getSessionId())
+        .set(AMEDIAMETRICS_PROP_SOURCE, toString(attributes.source).c_str())
+        .set(AMEDIAMETRICS_PROP_USAGE, toString(attributes.usage).c_str())
+        .record();
+}
+
 aaudio_result_t AAudioServiceStreamBase::open(const aaudio::AAudioStreamRequest &request) {
     AAudioEndpointManager &mEndpointManager = AAudioEndpointManager::getInstance();
     aaudio_result_t result = AAUDIO_OK;
@@ -154,6 +196,10 @@
     }
 
     setState(AAUDIO_STREAM_STATE_CLOSED);
+
+    mediametrics::LogItem(mMetricsId)
+        .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CLOSE)
+        .record();
     return result;
 }
 
@@ -173,8 +219,17 @@
  * An AAUDIO_SERVICE_EVENT_STARTED will be sent to the client when complete.
  */
 aaudio_result_t AAudioServiceStreamBase::start() {
+    const int64_t beginNs = AudioClock::getNanoseconds();
     aaudio_result_t result = AAUDIO_OK;
 
+    mediametrics::Defer defer([&] {
+        mediametrics::LogItem(mMetricsId)
+            .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_START)
+            .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(AudioClock::getNanoseconds() - beginNs))
+            .set(AMEDIAMETRICS_PROP_STATE, AudioGlobal_convertStreamStateToText(getState()))
+            .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)result)
+            .record(); });
+
     if (isRunning()) {
         return AAUDIO_OK;
     }
@@ -204,11 +259,20 @@
 }
 
 aaudio_result_t AAudioServiceStreamBase::pause() {
+    const int64_t beginNs = AudioClock::getNanoseconds();
     aaudio_result_t result = AAUDIO_OK;
     if (!isRunning()) {
         return result;
     }
 
+    mediametrics::Defer defer([&] {
+        mediametrics::LogItem(mMetricsId)
+            .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_PAUSE)
+            .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(AudioClock::getNanoseconds() - beginNs))
+            .set(AMEDIAMETRICS_PROP_STATE, AudioGlobal_convertStreamStateToText(getState()))
+            .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)result)
+            .record(); });
+
     // Send it now because the timestamp gets rounded up when stopStream() is called below.
     // Also we don't need the timestamps while we are shutting down.
     sendCurrentTimestamp();
@@ -222,7 +286,8 @@
     sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
     if (endpoint == nullptr) {
         ALOGE("%s() has no endpoint", __func__);
-        return AAUDIO_ERROR_INVALID_STATE;
+        result =  AAUDIO_ERROR_INVALID_STATE; // for MediaMetric tracking
+        return result;
     }
     result = endpoint->stopStream(this, mClientHandle);
     if (result != AAUDIO_OK) {
@@ -236,11 +301,20 @@
 }
 
 aaudio_result_t AAudioServiceStreamBase::stop() {
+    const int64_t beginNs = AudioClock::getNanoseconds();
     aaudio_result_t result = AAUDIO_OK;
     if (!isRunning()) {
         return result;
     }
 
+    mediametrics::Defer defer([&] {
+        mediametrics::LogItem(mMetricsId)
+            .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_STOP)
+            .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(AudioClock::getNanoseconds() - beginNs))
+            .set(AMEDIAMETRICS_PROP_STATE, AudioGlobal_convertStreamStateToText(getState()))
+            .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)result)
+            .record(); });
+
     setState(AAUDIO_STREAM_STATE_STOPPING);
 
     // Send it now because the timestamp gets rounded up when stopStream() is called below.
@@ -255,7 +329,8 @@
     sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
     if (endpoint == nullptr) {
         ALOGE("%s() has no endpoint", __func__);
-        return AAUDIO_ERROR_INVALID_STATE;
+        result =  AAUDIO_ERROR_INVALID_STATE; // for MediaMetric tracking
+        return result;
     }
     // TODO wait for data to be played out
     result = endpoint->stopStream(this, mClientHandle);
@@ -280,11 +355,20 @@
 }
 
 aaudio_result_t AAudioServiceStreamBase::flush() {
+    const int64_t beginNs = AudioClock::getNanoseconds();
     aaudio_result_t result = AAudio_isFlushAllowed(getState());
     if (result != AAUDIO_OK) {
         return result;
     }
 
+    mediametrics::Defer defer([&] {
+        mediametrics::LogItem(mMetricsId)
+            .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_FLUSH)
+            .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(AudioClock::getNanoseconds() - beginNs))
+            .set(AMEDIAMETRICS_PROP_STATE, AudioGlobal_convertStreamStateToText(getState()))
+            .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)result)
+            .record(); });
+
     // Data will get flushed when the client receives the FLUSHED event.
     sendServiceEvent(AAUDIO_SERVICE_EVENT_FLUSHED);
     setState(AAUDIO_STREAM_STATE_FLUSHED);
@@ -321,6 +405,10 @@
 
 void AAudioServiceStreamBase::disconnect() {
     if (getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
+        mediametrics::LogItem(mMetricsId)
+            .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_DISCONNECT)
+            .set(AMEDIAMETRICS_PROP_STATE, AudioGlobal_convertStreamStateToText(getState()))
+            .record();
         sendServiceEvent(AAUDIO_SERVICE_EVENT_DISCONNECTED);
         setState(AAUDIO_STREAM_STATE_DISCONNECTED);
     }
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index aaab567..79dd738 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -68,12 +68,15 @@
     // does not include EOL
     virtual std::string dump() const;
 
-    // -------------------------------------------------------------------
     /**
      * Open the device.
      */
     virtual aaudio_result_t open(const aaudio::AAudioStreamRequest &request) = 0;
 
+    // We log the CLOSE from the close() method. We needed this separate method to log the OPEN
+    // because we had to wait until we generated the handle.
+    void logOpen(aaudio_handle_t streamHandle);
+
     virtual aaudio_result_t close();
 
     /**
@@ -312,6 +315,8 @@
     android::sp<AAudioServiceEndpoint> mServiceEndpoint;
     android::wp<AAudioServiceEndpoint> mServiceEndpointWeak;
 
+    std::string mMetricsId;  // set once during open()
+
 private:
 
     /**
diff --git a/services/oboeservice/Android.bp b/services/oboeservice/Android.bp
index 64d835b..8b1e2c0 100644
--- a/services/oboeservice/Android.bp
+++ b/services/oboeservice/Android.bp
@@ -47,11 +47,13 @@
         "libaudioclient",
         "libaudioflinger",
         "libaudioutils",
+        "libmedia_helper",
+        "libmediametrics",
+        "libmediautils",
         "libbase",
         "libbinder",
         "libcutils",
         "liblog",
-        "libmediautils",
         "libutils",
     ],