Merge "Fix memory leak in playback time accumulation"
diff --git a/drm/OWNERS b/drm/OWNERS
index e788754..090c021 100644
--- a/drm/OWNERS
+++ b/drm/OWNERS
@@ -1 +1,3 @@
 jtinker@google.com
+kelzhan@google.com
+robertshih@google.com
diff --git a/media/codec2/components/base/SimpleC2Component.cpp b/media/codec2/components/base/SimpleC2Component.cpp
index 99ff450..434246f 100644
--- a/media/codec2/components/base/SimpleC2Component.cpp
+++ b/media/codec2/components/base/SimpleC2Component.cpp
@@ -763,6 +763,43 @@
     return hasQueuedWork;
 }
 
+int SimpleC2Component::getHalPixelFormatForBitDepth10(bool allowRGBA1010102) {
+    // Save supported hal pixel formats for bit depth of 10, the first time this is called
+    if (!mBitDepth10HalPixelFormats.size()) {
+        std::vector<int> halPixelFormats;
+        // TODO(b/178229371) Enable HAL_PIXEL_FORMAT_YCBCR_P010 once framework supports it
+        // halPixelFormats.push_back(HAL_PIXEL_FORMAT_YCBCR_P010);
+
+        // since allowRGBA1010102 can chance in each call, but mBitDepth10HalPixelFormats
+        // is populated only once, allowRGBA1010102 is not considered at this stage.
+        halPixelFormats.push_back(HAL_PIXEL_FORMAT_RGBA_1010102);
+
+        for (int halPixelFormat : halPixelFormats) {
+            std::shared_ptr<C2GraphicBlock> block;
+
+            uint32_t gpuConsumerFlags = halPixelFormat == HAL_PIXEL_FORMAT_RGBA_1010102
+                                                ? C2AndroidMemoryUsage::HW_TEXTURE_READ
+                                                : 0;
+            C2MemoryUsage usage = {C2MemoryUsage::CPU_READ | gpuConsumerFlags,
+                                   C2MemoryUsage::CPU_WRITE};
+            // TODO(b/214411172) Use AHardwareBuffer_isSupported once it supports P010
+            c2_status_t status =
+                    mOutputBlockPool->fetchGraphicBlock(320, 240, halPixelFormat, usage, &block);
+            if (status == C2_OK) {
+                mBitDepth10HalPixelFormats.push_back(halPixelFormat);
+            }
+        }
+        // Add YV12 in the end as a fall-back option
+        mBitDepth10HalPixelFormats.push_back(HAL_PIXEL_FORMAT_YV12);
+    }
+    // When RGBA1010102 is not allowed and if the first supported hal pixel is format is
+    // HAL_PIXEL_FORMAT_RGBA_1010102, then return HAL_PIXEL_FORMAT_YV12
+    if (!allowRGBA1010102 && mBitDepth10HalPixelFormats[0] == HAL_PIXEL_FORMAT_RGBA_1010102) {
+        return HAL_PIXEL_FORMAT_YV12;
+    }
+    // Return the first entry from supported formats
+    return mBitDepth10HalPixelFormats[0];
+}
 std::shared_ptr<C2Buffer> SimpleC2Component::createLinearBuffer(
         const std::shared_ptr<C2LinearBlock> &block, size_t offset, size_t size) {
     return C2Buffer::CreateLinearBuffer(block->share(offset, size, ::C2Fence()));
diff --git a/media/codec2/components/base/include/SimpleC2Component.h b/media/codec2/components/base/include/SimpleC2Component.h
index 3b4e212..d244f45 100644
--- a/media/codec2/components/base/include/SimpleC2Component.h
+++ b/media/codec2/components/base/include/SimpleC2Component.h
@@ -167,6 +167,7 @@
     static constexpr uint32_t NO_DRAIN = ~0u;
 
     C2ReadView mDummyReadView;
+    int getHalPixelFormatForBitDepth10(bool allowRGBA1010102);
 
 private:
     const std::shared_ptr<C2ComponentInterface> mIntf;
@@ -250,6 +251,7 @@
     class BlockingBlockPool;
     std::shared_ptr<BlockingBlockPool> mOutputBlockPool;
 
+    std::vector<int> mBitDepth10HalPixelFormats;
     SimpleC2Component() = delete;
 };
 
diff --git a/media/codec2/components/gav1/C2SoftGav1Dec.cpp b/media/codec2/components/gav1/C2SoftGav1Dec.cpp
index ffe72dc..2ed8541 100644
--- a/media/codec2/components/gav1/C2SoftGav1Dec.cpp
+++ b/media/codec2/components/gav1/C2SoftGav1Dec.cpp
@@ -335,7 +335,6 @@
           std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
       mIntf(intfImpl),
       mCodecCtx(nullptr) {
-  mIsFormatR10G10B10A2Supported = IsFormatR10G10B10A2SupportedForLegacyRendering();
   gettimeofday(&mTimeStart, nullptr);
   gettimeofday(&mTimeEnd, nullptr);
 }
@@ -633,25 +632,20 @@
     IntfImpl::Lock lock = mIntf->lock();
     std::shared_ptr<C2StreamColorAspectsInfo::output> codedColorAspects =
         mIntf->getColorAspects_l();
-
+    bool allowRGBA1010102 = false;
     if (codedColorAspects->primaries == C2Color::PRIMARIES_BT2020 &&
         codedColorAspects->matrix == C2Color::MATRIX_BT2020 &&
         codedColorAspects->transfer == C2Color::TRANSFER_ST2084) {
-      if (buffer->image_format != libgav1::kImageFormatYuv420) {
+      allowRGBA1010102 = true;
+    }
+    format = getHalPixelFormatForBitDepth10(allowRGBA1010102);
+    if ((format == HAL_PIXEL_FORMAT_RGBA_1010102) &&
+        (buffer->image_format != libgav1::kImageFormatYuv420)) {
         ALOGE("Only YUV420 output is supported when targeting RGBA_1010102");
-        mSignalledError = true;
-        work->result = C2_OMITTED;
-        work->workletsProcessed = 1u;
-        return false;
-      }
-      // TODO (b/201787956) For devices that do not support HAL_PIXEL_FORMAT_RGBA_1010102,
-      // HAL_PIXEL_FORMAT_YV12 is used as a temporary work around.
-      if (!mIsFormatR10G10B10A2Supported)  {
-        ALOGE("HAL_PIXEL_FORMAT_RGBA_1010102 isn't supported");
-        format = HAL_PIXEL_FORMAT_YV12;
-      } else {
-        format = HAL_PIXEL_FORMAT_RGBA_1010102;
-      }
+      mSignalledError = true;
+      work->result = C2_OMITTED;
+      work->workletsProcessed = 1u;
+      return false;
     }
   }
   C2MemoryUsage usage = {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
diff --git a/media/codec2/components/gav1/C2SoftGav1Dec.h b/media/codec2/components/gav1/C2SoftGav1Dec.h
index f82992d..134fa0d 100644
--- a/media/codec2/components/gav1/C2SoftGav1Dec.h
+++ b/media/codec2/components/gav1/C2SoftGav1Dec.h
@@ -82,7 +82,6 @@
 
   struct timeval mTimeStart;  // Time at the start of decode()
   struct timeval mTimeEnd;    // Time at the end of decode()
-  bool mIsFormatR10G10B10A2Supported;
 
   bool initDecoder();
   void getVuiParams(const libgav1::DecoderBuffer *buffer);
diff --git a/media/codec2/components/vpx/C2SoftVpxDec.cpp b/media/codec2/components/vpx/C2SoftVpxDec.cpp
index 0a27821..5fc89be 100644
--- a/media/codec2/components/vpx/C2SoftVpxDec.cpp
+++ b/media/codec2/components/vpx/C2SoftVpxDec.cpp
@@ -352,7 +352,6 @@
       mCodecCtx(nullptr),
       mCoreCount(1),
       mQueue(new Mutexed<ConversionQueue>) {
-      mIsFormatR10G10B10A2Supported = IsFormatR10G10B10A2SupportedForLegacyRendering();
 }
 
 C2SoftVpxDec::~C2SoftVpxDec() {
@@ -683,19 +682,13 @@
     if (img->fmt == VPX_IMG_FMT_I42016) {
         IntfImpl::Lock lock = mIntf->lock();
         std::shared_ptr<C2StreamColorAspectsTuning::output> defaultColorAspects = mIntf->getDefaultColorAspects_l();
-
+        bool allowRGBA1010102 = false;
         if (defaultColorAspects->primaries == C2Color::PRIMARIES_BT2020 &&
             defaultColorAspects->matrix == C2Color::MATRIX_BT2020 &&
             defaultColorAspects->transfer == C2Color::TRANSFER_ST2084) {
-            // TODO (b/201787956) For devices that do not support HAL_PIXEL_FORMAT_RGBA_1010102,
-            // HAL_PIXEL_FORMAT_YV12 is used as a temporary work around.
-            if (!mIsFormatR10G10B10A2Supported)  {
-                ALOGE("HAL_PIXEL_FORMAT_RGBA_1010102 isn't supported");
-                format = HAL_PIXEL_FORMAT_YV12;
-            } else {
-                format = HAL_PIXEL_FORMAT_RGBA_1010102;
-            }
+            allowRGBA1010102 = true;
         }
+        format = getHalPixelFormatForBitDepth10(allowRGBA1010102);
     }
     C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
     c2_status_t err = pool->fetchGraphicBlock(align(mWidth, 16), mHeight, format, usage, &block);
diff --git a/media/codec2/components/vpx/C2SoftVpxDec.h b/media/codec2/components/vpx/C2SoftVpxDec.h
index ade162d..2065165 100644
--- a/media/codec2/components/vpx/C2SoftVpxDec.h
+++ b/media/codec2/components/vpx/C2SoftVpxDec.h
@@ -80,7 +80,7 @@
     };
     std::shared_ptr<Mutexed<ConversionQueue>> mQueue;
     std::vector<sp<ConverterThread>> mConverterThreads;
-    bool mIsFormatR10G10B10A2Supported;
+
     status_t initDecoder();
     status_t destroyDecoder();
     void finishWork(uint64_t index, const std::unique_ptr<C2Work> &work,
diff --git a/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp b/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
index b761c35..bff9db5 100644
--- a/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
+++ b/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
@@ -118,22 +118,6 @@
 
 }  // namespace
 
-bool IsFormatR10G10B10A2SupportedForLegacyRendering() {
-    const AHardwareBuffer_Desc desc = {
-        .width = 320,
-        .height = 240,
-        .format = AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM,
-        .layers = 1,
-        .usage = AHARDWAREBUFFER_USAGE_CPU_READ_RARELY | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN |
-                 AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE,
-        .stride = 0,
-        .rfu0 = 0,
-        .rfu1 = 0,
-    };
-
-    return AHardwareBuffer_isSupported(&desc);
-}
-
 status_t ImageCopy(uint8_t *imgBase, const MediaImage2 *img, const C2GraphicView &view) {
     if (view.crop().width != img->mWidth || view.crop().height != img->mHeight) {
         return BAD_VALUE;
diff --git a/media/codec2/sfplugin/utils/Codec2BufferUtils.h b/media/codec2/sfplugin/utils/Codec2BufferUtils.h
index c4651a4..9fa642d 100644
--- a/media/codec2/sfplugin/utils/Codec2BufferUtils.h
+++ b/media/codec2/sfplugin/utils/Codec2BufferUtils.h
@@ -27,11 +27,6 @@
 namespace android {
 
 /**
- * Check if R10G10B10A2 is supported in legacy rendering path that involves GPU
- */
-bool IsFormatR10G10B10A2SupportedForLegacyRendering();
-
-/**
  * Converts an RGB view to planar YUV 420 media image.
  *
  * \param dstY       pointer to media image buffer
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index be81481..40efb38 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -834,33 +834,18 @@
     aps->onNewAudioModulesAvailable();
 }
 
-status_t AudioSystem::setDeviceConnectionState(audio_devices_t device,
-                                               audio_policy_dev_state_t state,
-                                               const char* device_address,
-                                               const char* device_name,
+status_t AudioSystem::setDeviceConnectionState(audio_policy_dev_state_t state,
+                                               const android::media::audio::common::AudioPort& port,
                                                audio_format_t encodedFormat) {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
-    const char* address = "";
-    const char* name = "";
 
     if (aps == 0) return PERMISSION_DENIED;
 
-    if (device_address != NULL) {
-        address = device_address;
-    }
-    if (device_name != NULL) {
-        name = device_name;
-    }
-
-    AudioDevice deviceAidl = VALUE_OR_RETURN_STATUS(
-            legacy2aidl_audio_device_AudioDevice(device, address));
-
     return statusTFromBinderStatus(
             aps->setDeviceConnectionState(
-                    deviceAidl,
                     VALUE_OR_RETURN_STATUS(
                             legacy2aidl_audio_policy_dev_state_t_AudioPolicyDeviceState(state)),
-                    name,
+                    port,
                     VALUE_OR_RETURN_STATUS(
                             legacy2aidl_audio_format_t_AudioFormatDescription(encodedFormat))));
 }
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 88e7396..292d92f 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -803,6 +803,12 @@
     return result.value_or(0);
 }
 
+status_t AudioFlingerClientAdapter::setDeviceConnectedState(
+        const struct audio_port_v7 *port, bool connected) {
+    media::AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
+            legacy2aidl_audio_port_v7_AudioPort(*port));
+    return statusTFromBinderStatus(mDelegate->setDeviceConnectedState(aidlPort, connected));
+}
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 // AudioFlingerServerAdapter
@@ -1292,4 +1298,10 @@
     return Status::ok();
 }
 
+Status AudioFlingerServerAdapter::setDeviceConnectedState(
+        const media::AudioPort& port, bool connected) {
+    audio_port_v7 portLegacy = VALUE_OR_RETURN_BINDER(aidl2legacy_AudioPort_audio_port_v7(port));
+    return Status::fromStatusT(mDelegate->setDeviceConnectedState(&portLegacy, connected));
+}
+
 } // namespace android
diff --git a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
index c55c66e..6afe023 100644
--- a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
@@ -225,4 +225,6 @@
     int getAAudioMixerBurstCount();
 
     int getAAudioHardwareBurstMinUsec();
+
+    void setDeviceConnectedState(in AudioPort devicePort, boolean connected);
 }
diff --git a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
index c3e8dfb..69328a7 100644
--- a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
@@ -50,6 +50,7 @@
 import android.media.audio.common.AudioMode;
 import android.media.audio.common.AudioProfile;
 import android.media.audio.common.AudioOffloadInfo;
+import android.media.audio.common.AudioPort;
 import android.media.audio.common.AudioSource;
 import android.media.audio.common.AudioStreamType;
 import android.media.audio.common.AudioUsage;
@@ -64,9 +65,8 @@
 interface IAudioPolicyService {
     oneway void onNewAudioModulesAvailable();
 
-    void setDeviceConnectionState(in AudioDevice device,
-                                  in AudioPolicyDeviceState state,
-                                  @utf8InCpp String deviceName,
+    void setDeviceConnectionState(in AudioPolicyDeviceState state,
+                                  in android.media.audio.common.AudioPort port,
                                   in AudioFormatDescription encodedFormat);
 
     AudioPolicyDeviceState getDeviceConnectionState(in AudioDevice device);
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 4280a6a..e0cb47e 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -30,6 +30,7 @@
 #include <android/media/ISpatializer.h>
 #include <android/media/audio/common/AudioMMapPolicyInfo.h>
 #include <android/media/audio/common/AudioMMapPolicyType.h>
+#include <android/media/audio/common/AudioPort.h>
 #include <media/AidlConversionUtil.h>
 #include <media/AudioContainers.h>
 #include <media/AudioDeviceTypeAddr.h>
@@ -263,8 +264,8 @@
     // IAudioPolicyService interface (see AudioPolicyInterface for method descriptions)
     //
     static void onNewAudioModulesAvailable();
-    static status_t setDeviceConnectionState(audio_devices_t device, audio_policy_dev_state_t state,
-                                             const char *device_address, const char *device_name,
+    static status_t setDeviceConnectionState(audio_policy_dev_state_t state,
+                                             const android::media::audio::common::AudioPort& port,
                                              audio_format_t encodedFormat);
     static audio_policy_dev_state_t getDeviceConnectionState(audio_devices_t device,
                                                                 const char *device_address);
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index b4ee4dc..e047378 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -358,6 +358,8 @@
     virtual int32_t getAAudioMixerBurstCount() = 0;
 
     virtual int32_t getAAudioHardwareBurstMinUsec() = 0;
+
+    virtual status_t setDeviceConnectedState(const struct audio_port_v7 *port, bool connected) = 0;
 };
 
 /**
@@ -454,14 +456,12 @@
     status_t setVibratorInfos(const std::vector<media::AudioVibratorInfo>& vibratorInfos) override;
     status_t updateSecondaryOutputs(
             const TrackSecondaryOutputsMap& trackSecondaryOutputs) override;
-
     status_t getMmapPolicyInfos(
             media::audio::common::AudioMMapPolicyType policyType,
             std::vector<media::audio::common::AudioMMapPolicyInfo> *policyInfos) override;
-
     int32_t getAAudioMixerBurstCount() override;
-
     int32_t getAAudioHardwareBurstMinUsec() override;
+    status_t setDeviceConnectedState(const struct audio_port_v7 *port, bool connected) override;
 
 private:
     const sp<media::IAudioFlingerService> mDelegate;
@@ -550,6 +550,7 @@
             GET_MMAP_POLICY_INFOS = media::BnAudioFlingerService::TRANSACTION_getMmapPolicyInfos,
             GET_AAUDIO_MIXER_BURST_COUNT = media::BnAudioFlingerService::TRANSACTION_getAAudioMixerBurstCount,
             GET_AAUDIO_HARDWARE_BURST_MIN_USEC = media::BnAudioFlingerService::TRANSACTION_getAAudioHardwareBurstMinUsec,
+            SET_DEVICE_CONNECTED_STATE = media::BnAudioFlingerService::TRANSACTION_setDeviceConnectedState,
         };
 
         /**
@@ -669,6 +670,7 @@
             std::vector<media::audio::common::AudioMMapPolicyInfo> *_aidl_return) override;
     Status getAAudioMixerBurstCount(int32_t* _aidl_return) override;
     Status getAAudioHardwareBurstMinUsec(int32_t* _aidl_return) override;
+    Status setDeviceConnectedState(const media::AudioPort& port, bool connected) override;
 
 private:
     const sp<AudioFlingerServerAdapter::Delegate> mDelegate;
diff --git a/media/libaudiohal/impl/DeviceHalHidl.cpp b/media/libaudiohal/impl/DeviceHalHidl.cpp
index 8b09d76..3180b7d 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalHidl.cpp
@@ -489,6 +489,32 @@
 }
 #endif
 
+status_t DeviceHalHidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
+    if (mDevice == 0) return NO_INIT;
+#if MAJOR_VERSION == 7 && MINOR_VERSION == 1
+    if (supportsSetConnectedState7_1) {
+        AudioPort hidlPort;
+        if (status_t result = HidlUtils::audioPortFromHal(*port, &hidlPort); result != NO_ERROR) {
+            return result;
+        }
+        Return<Result> ret = mDevice->setConnectedState_7_1(hidlPort, connected);
+        if (!ret.isOk() || ret != Result::NOT_SUPPORTED) {
+            return processReturn("setConnectedState_7_1", ret);
+        } else if (ret == Result::OK) {
+            return NO_ERROR;
+        }
+        supportsSetConnectedState7_1 = false;
+    }
+#endif
+    DeviceAddress hidlAddress;
+    if (status_t result = CoreUtils::deviceAddressFromHal(
+                    port->ext.device.type, port->ext.device.address, &hidlAddress);
+            result != NO_ERROR) {
+        return result;
+    }
+    return processReturn("setConnectedState", mDevice->setConnectedState(hidlAddress, connected));
+}
+
 status_t DeviceHalHidl::dump(int fd, const Vector<String16>& args) {
     if (mDevice == 0) return NO_INIT;
     native_handle_t* hidlHandle = native_handle_create(1, 0);
diff --git a/media/libaudiohal/impl/DeviceHalHidl.h b/media/libaudiohal/impl/DeviceHalHidl.h
index 104db40..cd9535e 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.h
+++ b/media/libaudiohal/impl/DeviceHalHidl.h
@@ -132,13 +132,16 @@
         return INVALID_OPERATION;
     }
 
+    status_t setConnectedState(const struct audio_port_v7 *port, bool connected) override;
+
     status_t dump(int fd, const Vector<String16>& args) override;
 
   private:
     friend class DevicesFactoryHalHidl;
     sp<::android::hardware::audio::CPP_VERSION::IDevice> mDevice;
-    sp<::android::hardware::audio::CPP_VERSION::IPrimaryDevice> mPrimaryDevice;
     // Null if it's not a primary device.
+    sp<::android::hardware::audio::CPP_VERSION::IPrimaryDevice> mPrimaryDevice;
+    bool supportsSetConnectedState7_1 = true;
 
     // Can not be constructed directly by clients.
     explicit DeviceHalHidl(const sp<::android::hardware::audio::CPP_VERSION::IDevice>& device);
diff --git a/media/libaudiohal/impl/DeviceHalLocal.cpp b/media/libaudiohal/impl/DeviceHalLocal.cpp
index 1384c1e..e473e41 100644
--- a/media/libaudiohal/impl/DeviceHalLocal.cpp
+++ b/media/libaudiohal/impl/DeviceHalLocal.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "DeviceHalLocal"
 //#define LOG_NDEBUG 0
 
+#include <media/AudioParameter.h>
 #include <utils/Log.h>
 
 #include "DeviceHalLocal.h"
@@ -232,6 +233,14 @@
     return INVALID_OPERATION;
 }
 
+status_t DeviceHalLocal::setConnectedState(const struct audio_port_v7 *port, bool connected) {
+    AudioParameter param(String8(port->ext.device.address));
+    const String8 key(connected ?
+            AudioParameter::keyDeviceConnect : AudioParameter::keyDeviceDisconnect);
+    param.addInt(key, port->ext.device.type);
+    return setParameters(param.toString());
+}
+
 status_t DeviceHalLocal::dump(int fd, const Vector<String16>& /* args */) {
     return mDev->dump(mDev, fd);
 }
diff --git a/media/libaudiohal/impl/DeviceHalLocal.h b/media/libaudiohal/impl/DeviceHalLocal.h
index b06e253..3e586cf 100644
--- a/media/libaudiohal/impl/DeviceHalLocal.h
+++ b/media/libaudiohal/impl/DeviceHalLocal.h
@@ -128,6 +128,8 @@
         return INVALID_OPERATION;
     }
 
+    status_t setConnectedState(const struct audio_port_v7 *port, bool connected) override;
+
     status_t dump(int fd, const Vector<String16>& args) override;
 
     void closeOutputStream(struct audio_stream_out *stream_out);
diff --git a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
index 70c3199..9ca7118 100644
--- a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
@@ -128,6 +128,9 @@
     virtual int32_t getAAudioMixerBurstCount() = 0;
     virtual int32_t getAAudioHardwareBurstMinUsec() = 0;
 
+    // Update the connection status of an external device.
+    virtual status_t setConnectedState(const struct audio_port_v7 *port, bool connected) = 0;
+
     virtual status_t dump(int fd, const Vector<String16>& args) = 0;
 
   protected:
diff --git a/media/libmedia/MediaResource.cpp b/media/libmedia/MediaResource.cpp
index ec52a49..a6f0b60 100644
--- a/media/libmedia/MediaResource.cpp
+++ b/media/libmedia/MediaResource.cpp
@@ -43,10 +43,10 @@
 }
 
 //static
-MediaResource MediaResource::CodecResource(bool secure, bool video, int64_t instanceCount) {
+MediaResource MediaResource::CodecResource(bool secure, SubType subType, int64_t instanceCount) {
     return MediaResource(
             secure ? Type::kSecureCodec : Type::kNonSecureCodec,
-            video ? SubType::kVideoCodec : SubType::kAudioCodec,
+            subType,
             instanceCount);
 }
 
diff --git a/media/libmedia/include/media/MediaResource.h b/media/libmedia/include/media/MediaResource.h
index 4712528..3b69d4f 100644
--- a/media/libmedia/include/media/MediaResource.h
+++ b/media/libmedia/include/media/MediaResource.h
@@ -37,7 +37,8 @@
     MediaResource(Type type, SubType subType, int64_t value);
     MediaResource(Type type, const std::vector<uint8_t> &id, int64_t value);
 
-    static MediaResource CodecResource(bool secure, bool video, int64_t instanceCount = 1);
+    static MediaResource CodecResource(bool secure, MediaResourceSubType subType,
+            int64_t instanceCount = 1);
     static MediaResource GraphicMemoryResource(int64_t value);
     static MediaResource CpuBoostResource();
     static MediaResource VideoBatteryResource();
@@ -62,6 +63,7 @@
         case MediaResource::SubType::kUnspecifiedSubType: return "unspecified";
         case MediaResource::SubType::kAudioCodec:         return "audio-codec";
         case MediaResource::SubType::kVideoCodec:         return "video-codec";
+        case MediaResource::SubType::kImageCodec:         return "image-codec";
         default:                                 return def;
     }
 }
diff --git a/media/libmediahelper/AudioValidator.cpp b/media/libmediahelper/AudioValidator.cpp
index 7eddbe1..5a0d517 100644
--- a/media/libmediahelper/AudioValidator.cpp
+++ b/media/libmediahelper/AudioValidator.cpp
@@ -47,8 +47,7 @@
         const effect_descriptor_t& desc, std::string_view bugNumber)
 {
     status_t status = NO_ERROR;
-    if (checkStringOverflow(desc.name)
-        | /* always */ checkStringOverflow(desc.implementor)) {
+    if (checkStringOverflow(desc.name) || checkStringOverflow(desc.implementor)) {
         status = BAD_VALUE;
     }
     return safetyNetLog(status, bugNumber);
diff --git a/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
index 8c86e16..609298f 100644
--- a/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
+++ b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
@@ -206,6 +206,7 @@
     }
 
     const char *mime;
+    bool isHeif = false;
     if (!trackMeta->findCString(kKeyMIMEType, &mime)) {
         ALOGE("image track has no mime type");
         return NULL;
@@ -215,6 +216,7 @@
         mime = MEDIA_MIMETYPE_VIDEO_HEVC;
         trackMeta = new MetaData(*trackMeta);
         trackMeta->setCString(kKeyMIMEType, mime);
+        isHeif = true;
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_AVIF)) {
         mime = MEDIA_MIMETYPE_VIDEO_AV1;
         trackMeta = new MetaData(*trackMeta);
@@ -240,6 +242,16 @@
         format->setInt32("width", thumbWidth);
     }
 
+    // If decoding tiled HEIF check decoder supports tile dimensions instead
+    if (!thumbnail && isHeif && format != NULL) {
+        int32_t tileWidth, tileHeight;
+        if (trackMeta->findInt32(kKeyTileWidth, &tileWidth) && tileWidth > 0
+                && trackMeta->findInt32(kKeyTileHeight, &tileHeight) && tileHeight > 0) {
+            format->setInt32("height", tileHeight);
+            format->setInt32("width", tileWidth);
+        }
+    }
+
     MediaCodecList::findMatchingCodecs(
             mime,
             false, /* encoder */
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index a0c8f8a..f81a5eb 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -4448,30 +4448,31 @@
     memset(&aspects, 0, sizeof(aspects));
     // Color metadata may have changed.
     sp<MetaData> meta = mSource->getFormat();
-    // TRICKY: using | instead of || because we want to execute all findInt32-s
-    if (meta->findInt32(kKeyColorPrimaries, (int32_t*)&aspects.mPrimaries)
-            | meta->findInt32(kKeyTransferFunction, (int32_t*)&aspects.mTransfer)
-            | meta->findInt32(kKeyColorMatrix, (int32_t*)&aspects.mMatrixCoeffs)
-            | meta->findInt32(kKeyColorRange, (int32_t*)&aspects.mRange)) {
-        int32_t primaries, transfer, coeffs;
-        bool fullRange;
-        ALOGV("primaries=%s transfer=%s matrix=%s range=%s",
-                asString(aspects.mPrimaries),
-                asString(aspects.mTransfer),
-                asString(aspects.mMatrixCoeffs),
-                asString(aspects.mRange));
-        ColorUtils::convertCodecColorAspectsToIsoAspects(
-                aspects, &primaries, &transfer, &coeffs, &fullRange);
-        mOwner->beginBox("colr");
-        mOwner->writeFourcc("nclx");
-        mOwner->writeInt16(primaries);
-        mOwner->writeInt16(transfer);
-        mOwner->writeInt16(coeffs);
-        mOwner->writeInt8(int8_t(fullRange ? 0x80 : 0x0));
-        mOwner->endBox(); // colr
-    } else {
+    bool findPrimaries = meta->findInt32(kKeyColorPrimaries, (int32_t*)&aspects.mPrimaries);
+    bool findTransfer = meta->findInt32(kKeyTransferFunction, (int32_t*)&aspects.mTransfer);
+    bool findMatrix = meta->findInt32(kKeyColorMatrix, (int32_t*)&aspects.mMatrixCoeffs);
+    bool findRange = meta->findInt32(kKeyColorRange, (int32_t*)&aspects.mRange);
+    if (!findPrimaries && !findTransfer && !findMatrix && !findRange) {
         ALOGV("no color information");
+        return;
     }
+
+    int32_t primaries, transfer, coeffs;
+    bool fullRange;
+    ALOGV("primaries=%s transfer=%s matrix=%s range=%s",
+            asString(aspects.mPrimaries),
+            asString(aspects.mTransfer),
+            asString(aspects.mMatrixCoeffs),
+            asString(aspects.mRange));
+    ColorUtils::convertCodecColorAspectsToIsoAspects(
+            aspects, &primaries, &transfer, &coeffs, &fullRange);
+    mOwner->beginBox("colr");
+    mOwner->writeFourcc("nclx");
+    mOwner->writeInt16(primaries);
+    mOwner->writeInt16(transfer);
+    mOwner->writeInt16(coeffs);
+    mOwner->writeInt8(int8_t(fullRange ? 0x80 : 0x0));
+    mOwner->endBox(); // colr
 }
 
 void MPEG4Writer::Track::writeMdcvAndClliBoxes() {
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index e9dcb26..c0e69d2 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -102,6 +102,8 @@
 static const char *kCodecMode = "android.media.mediacodec.mode";    /* audio, video */
 static const char *kCodecModeVideo = "video";            /* values returned for kCodecMode */
 static const char *kCodecModeAudio = "audio";
+static const char *kCodecModeImage = "image";
+static const char *kCodecModeUnknown = "unknown";
 static const char *kCodecEncoder = "android.media.mediacodec.encoder"; /* 0,1 */
 static const char *kCodecSecure = "android.media.mediacodec.secure";   /* 0, 1 */
 static const char *kCodecWidth = "android.media.mediacodec.width";     /* 0..n */
@@ -656,6 +658,24 @@
     notify->post();
 }
 
+static MediaResourceSubType toMediaResourceSubType(MediaCodec::Domain domain) {
+    switch (domain) {
+        case MediaCodec::DOMAIN_VIDEO: return MediaResourceSubType::kVideoCodec;
+        case MediaCodec::DOMAIN_AUDIO: return MediaResourceSubType::kAudioCodec;
+        case MediaCodec::DOMAIN_IMAGE: return MediaResourceSubType::kImageCodec;
+        default:                       return MediaResourceSubType::kUnspecifiedSubType;
+    }
+}
+
+static const char * toCodecMode(MediaCodec::Domain domain) {
+    switch (domain) {
+        case MediaCodec::DOMAIN_VIDEO: return kCodecModeVideo;
+        case MediaCodec::DOMAIN_AUDIO: return kCodecModeAudio;
+        case MediaCodec::DOMAIN_IMAGE: return kCodecModeImage;
+        default:                       return kCodecModeUnknown;
+    }
+}
+
 }  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -751,9 +771,9 @@
       mFlags(0),
       mStickyError(OK),
       mSoftRenderer(NULL),
-      mIsVideo(false),
-      mVideoWidth(0),
-      mVideoHeight(0),
+      mDomain(DOMAIN_UNKNOWN),
+      mWidth(0),
+      mHeight(0),
       mRotationDegrees(0),
       mHDRMetadataFlags(0),
       mDequeueInputTimeoutGeneration(0),
@@ -1165,7 +1185,7 @@
         });
     }
 
-    if (mIsVideo && (mFlags & kFlagIsEncoder)) {
+    if (mDomain == DOMAIN_VIDEO && (mFlags & kFlagIsEncoder)) {
         mBytesInput += buffer->size();
         mFramesInput++;
     }
@@ -1194,7 +1214,7 @@
 
     CHECK_NE(mState, UNINITIALIZED);
 
-    if (mIsVideo && (mFlags & kFlagIsEncoder)) {
+    if (mDomain == DOMAIN_VIDEO && (mFlags & kFlagIsEncoder)) {
         int32_t flags = 0;
         (void) buffer->meta()->findInt32("flags", &flags);
 
@@ -1402,7 +1422,13 @@
         mCodecInfo->getSupportedMediaTypes(&mediaTypes);
         for (size_t i = 0; i < mediaTypes.size(); ++i) {
             if (mediaTypes[i].startsWith("video/")) {
-                mIsVideo = true;
+                mDomain = DOMAIN_VIDEO;
+                break;
+            } else if (mediaTypes[i].startsWith("audio/")) {
+                mDomain = DOMAIN_AUDIO;
+                break;
+            } else if (mediaTypes[i].startsWith("image/")) {
+                mDomain = DOMAIN_IMAGE;
                 break;
             }
         }
@@ -1415,7 +1441,7 @@
         return NAME_NOT_FOUND;
     }
 
-    if (mIsVideo) {
+    if (mDomain == DOMAIN_VIDEO) {
         // video codec needs dedicated looper
         if (mCodecLooper == NULL) {
             mCodecLooper = new ALooper;
@@ -1448,17 +1474,16 @@
 
     if (mMetricsHandle != 0) {
         mediametrics_setCString(mMetricsHandle, kCodecCodec, name.c_str());
-        mediametrics_setCString(mMetricsHandle, kCodecMode,
-                                mIsVideo ? kCodecModeVideo : kCodecModeAudio);
+        mediametrics_setCString(mMetricsHandle, kCodecMode, toCodecMode(mDomain));
     }
 
-    if (mIsVideo) {
+    if (mDomain == DOMAIN_VIDEO) {
         mBatteryChecker = new BatteryChecker(new AMessage(kWhatCheckBatteryStats, this));
     }
 
     status_t err;
     std::vector<MediaResourceParcel> resources;
-    resources.push_back(MediaResource::CodecResource(secureCodec, mIsVideo));
+    resources.push_back(MediaResource::CodecResource(secureCodec, toMediaResourceSubType(mDomain)));
     for (int i = 0; i <= kMaxRetry; ++i) {
         if (i > 0) {
             // Don't try to reclaim resource for the first time.
@@ -1539,16 +1564,16 @@
         mediametrics_setCString(mMetricsHandle, kCodecLogSessionId, mLogSessionId.c_str());
     }
 
-    if (mIsVideo) {
-        format->findInt32("width", &mVideoWidth);
-        format->findInt32("height", &mVideoHeight);
+    if (mDomain == DOMAIN_VIDEO || mDomain == DOMAIN_IMAGE) {
+        format->findInt32("width", &mWidth);
+        format->findInt32("height", &mHeight);
         if (!format->findInt32("rotation-degrees", &mRotationDegrees)) {
             mRotationDegrees = 0;
         }
 
         if (mMetricsHandle != 0) {
-            mediametrics_setInt32(mMetricsHandle, kCodecWidth, mVideoWidth);
-            mediametrics_setInt32(mMetricsHandle, kCodecHeight, mVideoHeight);
+            mediametrics_setInt32(mMetricsHandle, kCodecWidth, mWidth);
+            mediametrics_setInt32(mMetricsHandle, kCodecHeight, mHeight);
             mediametrics_setInt32(mMetricsHandle, kCodecRotation, mRotationDegrees);
             int32_t maxWidth = 0;
             if (format->findInt32("max-width", &maxWidth)) {
@@ -1562,21 +1587,23 @@
             if (format->findInt32("color-format", &colorFormat)) {
                 mediametrics_setInt32(mMetricsHandle, kCodecColorFormat, colorFormat);
             }
-            float frameRate = -1.0;
-            if (format->findFloat("frame-rate", &frameRate)) {
-                mediametrics_setDouble(mMetricsHandle, kCodecFrameRate, frameRate);
-            }
-            float captureRate = -1.0;
-            if (format->findFloat("capture-rate", &captureRate)) {
-                mediametrics_setDouble(mMetricsHandle, kCodecCaptureRate, captureRate);
-            }
-            float operatingRate = -1.0;
-            if (format->findFloat("operating-rate", &operatingRate)) {
-                mediametrics_setDouble(mMetricsHandle, kCodecOperatingRate, operatingRate);
-            }
-            int32_t priority = -1;
-            if (format->findInt32("priority", &priority)) {
-                mediametrics_setInt32(mMetricsHandle, kCodecPriority, priority);
+            if (mDomain == DOMAIN_VIDEO) {
+                float frameRate = -1.0;
+                if (format->findFloat("frame-rate", &frameRate)) {
+                    mediametrics_setDouble(mMetricsHandle, kCodecFrameRate, frameRate);
+                }
+                float captureRate = -1.0;
+                if (format->findFloat("capture-rate", &captureRate)) {
+                    mediametrics_setDouble(mMetricsHandle, kCodecCaptureRate, captureRate);
+                }
+                float operatingRate = -1.0;
+                if (format->findFloat("operating-rate", &operatingRate)) {
+                    mediametrics_setDouble(mMetricsHandle, kCodecOperatingRate, operatingRate);
+                }
+                int32_t priority = -1;
+                if (format->findInt32("priority", &priority)) {
+                    mediametrics_setInt32(mMetricsHandle, kCodecPriority, priority);
+                }
             }
             int32_t colorStandard = -1;
             if (format->findInt32(KEY_COLOR_STANDARD, &colorStandard)) {
@@ -1598,9 +1625,9 @@
         }
 
         // Prevent possible integer overflow in downstream code.
-        if (mVideoWidth < 0 || mVideoHeight < 0 ||
-               (uint64_t)mVideoWidth * mVideoHeight > (uint64_t)INT32_MAX / 4) {
-            ALOGE("Invalid size(s), width=%d, height=%d", mVideoWidth, mVideoHeight);
+        if (mWidth < 0 || mHeight < 0 ||
+               (uint64_t)mWidth * mHeight > (uint64_t)INT32_MAX / 4) {
+            ALOGE("Invalid size(s), width=%d, height=%d", mWidth, mHeight);
             return BAD_VALUE;
         }
 
@@ -1633,7 +1660,7 @@
     }
 
     // push min/max QP to MediaMetrics after shaping
-    if (mIsVideo && mMetricsHandle != 0) {
+    if (mDomain == DOMAIN_VIDEO && mMetricsHandle != 0) {
         int32_t qpIMin = -1;
         if (format->findInt32("video-qp-i-min", &qpIMin)) {
             mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPIMin, qpIMin);
@@ -1686,7 +1713,8 @@
 
     status_t err;
     std::vector<MediaResourceParcel> resources;
-    resources.push_back(MediaResource::CodecResource(mFlags & kFlagIsSecure, mIsVideo));
+    resources.push_back(MediaResource::CodecResource(mFlags & kFlagIsSecure,
+            toMediaResourceSubType(mDomain)));
     // Don't know the buffer size at this point, but it's fine to use 1 because
     // the reclaimResource call doesn't consider the requester's buffer size for now.
     resources.push_back(MediaResource::GraphicMemoryResource(1));
@@ -2267,7 +2295,7 @@
 }
 
 uint64_t MediaCodec::getGraphicBufferSize() {
-    if (!mIsVideo) {
+    if (mDomain != DOMAIN_VIDEO && mDomain != DOMAIN_IMAGE) {
         return 0;
     }
 
@@ -2275,7 +2303,7 @@
     size_t portNum = sizeof(mPortBuffers) / sizeof((mPortBuffers)[0]);
     for (size_t i = 0; i < portNum; ++i) {
         // TODO: this is just an estimation, we should get the real buffer size from ACodec.
-        size += mPortBuffers[i].size() * mVideoWidth * mVideoHeight * 3 / 2;
+        size += mPortBuffers[i].size() * mWidth * mHeight * 3 / 2;
     }
     return size;
 }
@@ -2287,7 +2315,8 @@
 
     status_t err;
     std::vector<MediaResourceParcel> resources;
-    resources.push_back(MediaResource::CodecResource(mFlags & kFlagIsSecure, mIsVideo));
+    resources.push_back(MediaResource::CodecResource(mFlags & kFlagIsSecure,
+            toMediaResourceSubType(mDomain)));
     // Don't know the buffer size at this point, but it's fine to use 1 because
     // the reclaimResource call doesn't consider the requester's buffer size for now.
     resources.push_back(MediaResource::GraphicMemoryResource(1));
@@ -3219,8 +3248,8 @@
                             : MediaCodecInfo::Attributes(0);
                     if (!(attr & MediaCodecInfo::kFlagIsSoftwareOnly)) {
                         // software codec is currently ignored.
-                        mResourceManagerProxy->addResource(
-                                MediaResource::CodecResource(mFlags & kFlagIsSecure, mIsVideo));
+                        mResourceManagerProxy->addResource(MediaResource::CodecResource(
+                            mFlags & kFlagIsSecure, toMediaResourceSubType(mDomain)));
                     }
 
                     postPendingRepliesAndDeferredMessages("kWhatComponentAllocated");
@@ -3386,7 +3415,7 @@
                     }
 
                     CHECK_EQ(mState, STARTING);
-                    if (mIsVideo) {
+                    if (mDomain == DOMAIN_VIDEO || mDomain == DOMAIN_IMAGE) {
                         mResourceManagerProxy->addResource(
                                 MediaResource::GraphicMemoryResource(getGraphicBufferSize()));
                     }
diff --git a/media/libstagefright/foundation/ColorUtils.cpp b/media/libstagefright/foundation/ColorUtils.cpp
index a5affb9..6dc8157 100644
--- a/media/libstagefright/foundation/ColorUtils.cpp
+++ b/media/libstagefright/foundation/ColorUtils.cpp
@@ -590,9 +590,10 @@
     uint32_t gfxRange = range;
     uint32_t gfxStandard = standard;
     uint32_t gfxTransfer = transfer;
-    // TRICKY: use & to ensure all three mappings are completed
-    if (!(sGfxRanges.map(range, &gfxRange) & sGfxStandards.map(standard, &gfxStandard)
-            & sGfxTransfers.map(transfer, &gfxTransfer))) {
+    bool mappedRange = sGfxRanges.map(range, &gfxRange);
+    bool mappedStandard = sGfxStandards.map(standard, &gfxStandard);
+    bool mappedTransfer = sGfxTransfers.map(transfer, &gfxTransfer);
+    if (! (mappedRange && mappedStandard && mappedTransfer)) {
         ALOGW("could not safely map platform color aspects (R:%u(%s) S:%u(%s) T:%u(%s) to "
               "graphics dataspace (R:%u S:%u T:%u)",
               range, asString(range), standard, asString(standard), transfer, asString(transfer),
@@ -626,9 +627,10 @@
     CU::ColorRange    cuRange    = CU::kColorRangeUnspecified;
     CU::ColorStandard cuStandard = CU::kColorStandardUnspecified;
     CU::ColorTransfer cuTransfer = CU::kColorTransferUnspecified;
-    // TRICKY: use & to ensure all three mappings are completed
-    if (!(sGfxRanges.map(gfxRange, &cuRange) & sGfxStandards.map(gfxStandard, &cuStandard)
-            & sGfxTransfers.map(gfxTransfer, &cuTransfer))) {
+    bool mappedRange = sGfxRanges.map(gfxRange, &cuRange);
+    bool mappedStandard = sGfxStandards.map(gfxStandard, &cuStandard);
+    bool mappedTransfer = sGfxTransfers.map(gfxTransfer, &cuTransfer);
+    if (! (mappedRange && mappedStandard && mappedTransfer)) {
         ALOGW("could not safely map graphics dataspace (R:%u S:%u T:%u) to "
               "platform color aspects (R:%u(%s) S:%u(%s) T:%u(%s)",
               gfxRange, gfxStandard, gfxTransfer,
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index b9a3197..29a87e9 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -70,6 +70,13 @@
 using aidl::android::media::MediaResourceParcel;
 
 struct MediaCodec : public AHandler {
+    enum Domain {
+        DOMAIN_UNKNOWN = 0,
+        DOMAIN_VIDEO = 1,
+        DOMAIN_AUDIO = 2,
+        DOMAIN_IMAGE = 3
+    };
+
     enum ConfigureFlags {
         CONFIGURE_FLAG_ENCODE           = 1,
         CONFIGURE_FLAG_USE_BLOCK_MODEL  = 2,
@@ -438,10 +445,10 @@
 
     sp<ResourceManagerServiceProxy> mResourceManagerProxy;
 
-    bool mIsVideo;
+    Domain mDomain;
     AString mLogSessionId;
-    int32_t mVideoWidth;
-    int32_t mVideoHeight;
+    int32_t mWidth;
+    int32_t mHeight;
     int32_t mRotationDegrees;
     int32_t mAllowFrameDroppingBySurface;
 
diff --git a/media/libwatchdog/Android.bp b/media/libwatchdog/Android.bp
index 411c206..5506a73 100644
--- a/media/libwatchdog/Android.bp
+++ b/media/libwatchdog/Android.bp
@@ -39,7 +39,7 @@
         darwin: {
             enabled: false,
         },
-        linux_glibc: {
+        glibc: {
             cflags: [
                 "-Dsigev_notify_thread_id=_sigev_un._tid",
             ],
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 43f79ce..5b53331 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -386,6 +386,24 @@
     return mAAudioHwBurstMinMicros;
 }
 
+status_t AudioFlinger::setDeviceConnectedState(const struct audio_port_v7 *port, bool connected) {
+    status_t final_result = NO_INIT;
+    Mutex::Autolock _l(mLock);
+    AutoMutex lock(mHardwareLock);
+    mHardwareStatus = AUDIO_HW_SET_CONNECTED_STATE;
+    for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+        sp<DeviceHalInterface> dev = mAudioHwDevs.valueAt(i)->hwDevice();
+        status_t result = dev->setConnectedState(port, connected);
+        // Same logic as with setParameter: it's a success if at least one
+        // HAL module accepts the update.
+        if (final_result != NO_ERROR) {
+            final_result = result;
+        }
+    }
+    mHardwareStatus = AUDIO_HW_IDLE;
+    return final_result;
+}
+
 // getDefaultVibratorInfo_l must be called with AudioFlinger lock held.
 std::optional<media::AudioVibratorInfo> AudioFlinger::getDefaultVibratorInfo_l() {
     if (mAudioVibratorInfos.empty()) {
@@ -4334,6 +4352,7 @@
         case TransactionCode::SET_AUDIO_PORT_CONFIG:
         case TransactionCode::SET_RECORD_SILENCED:
         case TransactionCode::AUDIO_POLICY_READY:
+        case TransactionCode::SET_DEVICE_CONNECTED_STATE:
             ALOGW("%s: transaction %d received from PID %d",
                   __func__, code, IPCThreadState::self()->getCallingPid());
             // return status only for non void methods
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 8c546cc..59f22eb 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -290,6 +290,8 @@
 
     virtual int32_t getAAudioHardwareBurstMinUsec();
 
+    virtual status_t setDeviceConnectedState(const struct audio_port_v7 *port, bool connected);
+
     status_t onTransactWrapper(TransactionCode code, const Parcel& data, uint32_t flags,
         const std::function<status_t()>& delegate) override;
 
@@ -912,6 +914,7 @@
         AUDIO_HW_SET_MASTER_MUTE,       // set_master_mute
         AUDIO_HW_GET_MASTER_MUTE,       // get_master_mute
         AUDIO_HW_GET_MICROPHONES,       // getMicrophones
+        AUDIO_HW_SET_CONNECTED_STATE,   // setConnectedState
     };
 
     mutable     hardware_call_state                 mHardwareStatus;    // for dump only
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index e8e478b..5b2b87e 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -105,10 +105,8 @@
     virtual void onNewAudioModulesAvailable() = 0;
 
     // indicate a change in device connection status
-    virtual status_t setDeviceConnectionState(audio_devices_t device,
-                                              audio_policy_dev_state_t state,
-                                              const char *device_address,
-                                              const char *device_name,
+    virtual status_t setDeviceConnectionState(audio_policy_dev_state_t state,
+                                              const android::media::audio::common::AudioPort& port,
                                               audio_format_t encodedFormat) = 0;
     // retrieve a device connection status
     virtual audio_policy_dev_state_t getDeviceConnectionState(audio_devices_t device,
@@ -546,6 +544,8 @@
 
     virtual status_t updateSecondaryOutputs(
             const TrackSecondaryOutputsMap& trackSecondaryOutputs) = 0;
+
+    virtual status_t setDeviceConnectedState(const struct audio_port_v7 *port, bool connected) = 0;
 };
 
     // These are the signatures of createAudioPolicyManager/destroyAudioPolicyManager
diff --git a/services/audiopolicy/managerdefault/Android.bp b/services/audiopolicy/managerdefault/Android.bp
index 0165dc8..4b4817e 100644
--- a/services/audiopolicy/managerdefault/Android.bp
+++ b/services/audiopolicy/managerdefault/Android.bp
@@ -36,6 +36,8 @@
         "libaudiopolicyenginedefault",
         "framework-permission-aidl-cpp",
         "libaudioclient_aidl_conversion",
+        "android.media.audio.common.types-V1-cpp",
+        "audioclient-types-aidl-cpp",
     ],
 
     header_libs: [
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index bd295ce..cc36c08 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -38,6 +38,7 @@
 #include <vector>
 
 #include <Serializer.h>
+#include <android/media/audio/common/AudioPort.h>
 #include <cutils/bitops.h>
 #include <cutils/properties.h>
 #include <media/AudioParameter.h>
@@ -53,6 +54,10 @@
 
 namespace android {
 
+using android::media::audio::common::AudioDevice;
+using android::media::audio::common::AudioDeviceAddress;
+using android::media::audio::common::AudioPortDeviceExt;
+using android::media::audio::common::AudioPortExt;
 using content::AttributionSourceState;
 
 //FIXME: workaround for truncated touch sounds
@@ -97,44 +102,80 @@
 // AudioPolicyInterface implementation
 // ----------------------------------------------------------------------------
 
-status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device,
-                                                      audio_policy_dev_state_t state,
-                                                      const char *device_address,
-                                                      const char *device_name,
-                                                      audio_format_t encodedFormat)
-{
-    status_t status = setDeviceConnectionStateInt(device, state, device_address,
-                                                  device_name, encodedFormat);
+status_t AudioPolicyManager::setDeviceConnectionState(audio_policy_dev_state_t state,
+        const android::media::audio::common::AudioPort& port, audio_format_t encodedFormat) {
+    status_t status = setDeviceConnectionStateInt(state, port, encodedFormat);
     nextAudioPortGeneration();
     return status;
 }
 
+status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device,
+                                                      audio_policy_dev_state_t state,
+                                                      const char* device_address,
+                                                      const char* device_name,
+                                                      audio_format_t encodedFormat) {
+    media::AudioPort aidlPort;
+    if (status_t status = deviceToAudioPort(device, device_address, device_name, &aidlPort);
+        status == OK) {
+        return setDeviceConnectionState(state, aidlPort.hal, encodedFormat);
+    } else {
+        ALOGE("Failed to convert to AudioPort Parcelable: %s", statusToString(status).c_str());
+        return status;
+    }
+}
+
 void AudioPolicyManager::broadcastDeviceConnectionState(const sp<DeviceDescriptor> &device,
                                                         audio_policy_dev_state_t state)
 {
-    AudioParameter param(String8(device->address().c_str()));
-    const String8 key(state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE ?
-                AudioParameter::keyDeviceConnect : AudioParameter::keyDeviceDisconnect);
-    param.addInt(key, device->type());
-    mpClientInterface->setParameters(AUDIO_IO_HANDLE_NONE, param.toString());
+    audio_port_v7 devicePort;
+    device->toAudioPort(&devicePort);
+    if (status_t status = mpClientInterface->setDeviceConnectedState(
+                    &devicePort, state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
+            status != OK) {
+        ALOGE("Error %d while setting connected state for device %s", status,
+                device->getDeviceTypeAddr().toString(false).c_str());
+    }
+}
+
+status_t AudioPolicyManager::setDeviceConnectionStateInt(
+        audio_policy_dev_state_t state, const android::media::audio::common::AudioPort& port,
+        audio_format_t encodedFormat) {
+    // TODO: b/211601178 Forward 'port' to Audio HAL via mHwModules. For now, only device_type,
+    // device_address and device_name are forwarded.
+    if (port.ext.getTag() != AudioPortExt::device) {
+        return BAD_VALUE;
+    }
+    audio_devices_t device_type;
+    std::string device_address;
+    if (status_t status = aidl2legacy_AudioDevice_audio_device(
+                port.ext.get<AudioPortExt::device>().device, &device_type, &device_address);
+        status != OK) {
+        return status;
+    };
+    const char* device_name = port.name.c_str();
+    // connect/disconnect only 1 device at a time
+    if (!audio_is_output_device(device_type) && !audio_is_input_device(device_type))
+        return BAD_VALUE;
+
+    sp<DeviceDescriptor> device = mHwModules.getDeviceDescriptor(
+            device_type, device_address.c_str(), device_name, encodedFormat,
+            state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
+    return device ? setDeviceConnectionStateInt(device, state) : INVALID_OPERATION;
 }
 
 status_t AudioPolicyManager::setDeviceConnectionStateInt(audio_devices_t deviceType,
                                                          audio_policy_dev_state_t state,
-                                                         const char *device_address,
-                                                         const char *device_name,
-                                                         audio_format_t encodedFormat)
-{
-    ALOGV("setDeviceConnectionStateInt() device: 0x%X, state %d, address %s name %s format 0x%X",
-            deviceType, state, device_address, device_name, encodedFormat);
-
-    // connect/disconnect only 1 device at a time
-    if (!audio_is_output_device(deviceType) && !audio_is_input_device(deviceType)) return BAD_VALUE;
-
-    sp<DeviceDescriptor> device =
-            mHwModules.getDeviceDescriptor(deviceType, device_address, device_name, encodedFormat,
-                                           state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
-    return device ? setDeviceConnectionStateInt(device, state) : INVALID_OPERATION;
+                                                         const char* device_address,
+                                                         const char* device_name,
+                                                         audio_format_t encodedFormat) {
+    media::AudioPort aidlPort;
+    if (status_t status = deviceToAudioPort(deviceType, device_address, device_name, &aidlPort);
+        status == OK) {
+        return setDeviceConnectionStateInt(state, aidlPort.hal, encodedFormat);
+    } else {
+        ALOGE("Failed to convert to AudioPort Parcelable: %s", statusToString(status).c_str());
+        return status;
+    }
 }
 
 status_t AudioPolicyManager::setDeviceConnectionStateInt(const sp<DeviceDescriptor> &device,
@@ -399,6 +440,14 @@
     return BAD_VALUE;
 }
 
+status_t AudioPolicyManager::deviceToAudioPort(audio_devices_t device, const char* device_address,
+                                               const char* device_name,
+                                               media::AudioPort* aidlPort) {
+    DeviceDescriptorBase devDescr(device, device_address);
+    devDescr.setName(device_name);
+    return devDescr.writeToParcelable(aidlPort);
+}
+
 void AudioPolicyManager::setEngineDeviceConnectionState(const sp<DeviceDescriptor> device,
                                       audio_policy_dev_state_t state) {
 
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 165ac13..a145c70 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -35,6 +35,7 @@
 #include <media/PatchBuilder.h>
 #include "AudioPolicyInterface.h"
 
+#include <android/media/audio/common/AudioPort.h>
 #include <AudioPolicyManagerObserver.h>
 #include <AudioPolicyConfig.h>
 #include <PolicyAudioPort.h>
@@ -95,11 +96,8 @@
         virtual ~AudioPolicyManager();
 
         // AudioPolicyInterface
-        virtual status_t setDeviceConnectionState(audio_devices_t device,
-                                                          audio_policy_dev_state_t state,
-                                                          const char *device_address,
-                                                          const char *device_name,
-                                                          audio_format_t encodedFormat);
+        virtual status_t setDeviceConnectionState(audio_policy_dev_state_t state,
+                const android::media::audio::common::AudioPort& port, audio_format_t encodedFormat);
         virtual audio_policy_dev_state_t getDeviceConnectionState(audio_devices_t device,
                                                                               const char *device_address);
         virtual status_t handleDeviceConfigChange(audio_devices_t device,
@@ -911,6 +909,16 @@
         PatchBuilder buildMsdPatch(bool msdIsSource, const sp<DeviceDescriptor> &device) const;
         status_t setMsdOutputPatches(const DeviceVector *outputDevices = nullptr);
         void releaseMsdOutputPatches(const DeviceVector& devices);
+
+        // Overload of setDeviceConnectionState()
+        status_t setDeviceConnectionState(audio_devices_t deviceType,
+                                          audio_policy_dev_state_t state,
+                                          const char* device_address, const char* device_name,
+                                          audio_format_t encodedFormat);
+
+        // Called by setDeviceConnectionState()
+        status_t deviceToAudioPort(audio_devices_t deviceType, const char* device_address,
+                                   const char* device_name, media::AudioPort* aidPort);
 private:
         void onNewAudioModulesAvailableInt(DeviceVector *newDevices);
 
@@ -1030,6 +1038,9 @@
         bool     isValidAttributes(const audio_attributes_t *paa);
 
         // Called by setDeviceConnectionState().
+        status_t setDeviceConnectionStateInt(audio_policy_dev_state_t state,
+                                             const android::media::audio::common::AudioPort& port,
+                                             audio_format_t encodedFormat);
         status_t setDeviceConnectionStateInt(audio_devices_t deviceType,
                                              audio_policy_dev_state_t state,
                                              const char *device_address,
diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
index aaf6fba..63a1e71 100644
--- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
@@ -307,4 +307,15 @@
     return af->updateSecondaryOutputs(trackSecondaryOutputs);
 }
 
+status_t AudioPolicyService::AudioPolicyClient::setDeviceConnectedState(
+        const struct audio_port_v7 *port, bool connected) {
+    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+    if (af == nullptr) {
+        ALOGW("%s: could not get AudioFlinger", __func__);
+        return PERMISSION_DENIED;
+    }
+    return af->setDeviceConnectedState(port, connected);
+}
+
+
 } // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 87a350f..582c048 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -119,14 +119,9 @@
 }
 
 Status AudioPolicyService::setDeviceConnectionState(
-        const AudioDevice& deviceAidl,
         media::AudioPolicyDeviceState stateAidl,
-        const std::string& deviceNameAidl,
+        const android::media::audio::common::AudioPort& port,
         const AudioFormatDescription& encodedFormatAidl) {
-    audio_devices_t device;
-    std::string address;
-    RETURN_BINDER_STATUS_IF_ERROR(
-            aidl2legacy_AudioDevice_audio_device(deviceAidl, &device, &address));
     audio_policy_dev_state_t state = VALUE_OR_RETURN_BINDER_STATUS(
             aidl2legacy_AudioPolicyDeviceState_audio_policy_dev_state_t(stateAidl));
     audio_format_t encodedFormat = VALUE_OR_RETURN_BINDER_STATUS(
@@ -147,7 +142,7 @@
     Mutex::Autolock _l(mLock);
     AutoCallerClear acc;
     status_t status = mAudioPolicyManager->setDeviceConnectionState(
-            device, state, address.c_str(), deviceNameAidl.c_str(), encodedFormat);
+            state, port, encodedFormat);
     if (status == NO_ERROR) {
         onCheckSpatializer_l();
     }
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index ac5af6b..39f2c97 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -82,9 +82,8 @@
     //
     binder::Status onNewAudioModulesAvailable() override;
     binder::Status setDeviceConnectionState(
-            const AudioDevice& device,
             media::AudioPolicyDeviceState state,
-            const std::string& deviceName,
+            const android::media::audio::common::AudioPort& port,
             const AudioFormatDescription& encodedFormat) override;
     binder::Status getDeviceConnectionState(const AudioDevice& device,
                                             media::AudioPolicyDeviceState* _aidl_return) override;
@@ -808,6 +807,9 @@
         status_t updateSecondaryOutputs(
                 const TrackSecondaryOutputsMap& trackSecondaryOutputs) override;
 
+        status_t setDeviceConnectedState(
+                const struct audio_port_v7 *port, bool connected) override;
+
      private:
         AudioPolicyService *mAudioPolicyService;
     };
diff --git a/services/audiopolicy/tests/Android.bp b/services/audiopolicy/tests/Android.bp
index 8fbe8b2..2e220bc 100644
--- a/services/audiopolicy/tests/Android.bp
+++ b/services/audiopolicy/tests/Android.bp
@@ -31,7 +31,7 @@
 
     static_libs: [
         "libaudiopolicycomponents",
-        "libgmock"
+        "libgmock",
     ],
 
     header_libs: [
@@ -65,6 +65,12 @@
         "liblog",
         "libmedia_helper",
         "libutils",
+        "android.media.audio.common.types-V1-cpp",
+        "libaudioclient_aidl_conversion",
+        "libstagefright_foundation",
+        "libshmemcompat",
+        "libshmemutil",
+        "audioclient-types-aidl-cpp",
     ],
 
     static_libs: ["libaudiopolicycomponents"],
diff --git a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
index 84b40d2..adef8f1 100644
--- a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
@@ -103,6 +103,11 @@
         ++mAudioPortListUpdateCount;
     }
 
+    status_t setDeviceConnectedState(
+            const struct audio_port_v7 *port __unused, bool connected __unused) override {
+        return NO_ERROR;
+    }
+
     // Helper methods for tests
     size_t getActivePatchesCount() const { return mActivePatches.size(); }
 
diff --git a/services/audiopolicy/tests/AudioPolicyTestClient.h b/services/audiopolicy/tests/AudioPolicyTestClient.h
index 4e0735b..da85658 100644
--- a/services/audiopolicy/tests/AudioPolicyTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyTestClient.h
@@ -96,6 +96,10 @@
             const TrackSecondaryOutputsMap& trackSecondaryOutputs __unused) override {
         return NO_INIT;
     }
+    status_t setDeviceConnectedState(
+            const struct audio_port_v7 *port __unused, bool connected __unused) override {
+        return NO_INIT;
+    }
 };
 
 } // namespace android
diff --git a/services/audiopolicy/tests/AudioPolicyTestManager.h b/services/audiopolicy/tests/AudioPolicyTestManager.h
index ff06937..7441f20 100644
--- a/services/audiopolicy/tests/AudioPolicyTestManager.h
+++ b/services/audiopolicy/tests/AudioPolicyTestManager.h
@@ -35,6 +35,8 @@
     using AudioPolicyManager::getAudioPatches;
     using AudioPolicyManager::getDirectPlaybackSupport;
     using AudioPolicyManager::getDirectProfilesForAttributes;
+    using AudioPolicyManager::setDeviceConnectionState;
+    using AudioPolicyManager::deviceToAudioPort;
     uint32_t getAudioPortGeneration() const { return mAudioPortGeneration; }
 };
 
diff --git a/services/audiopolicy/tests/audio_health_tests.cpp b/services/audiopolicy/tests/audio_health_tests.cpp
index df4389b..10f8dc0 100644
--- a/services/audiopolicy/tests/audio_health_tests.cpp
+++ b/services/audiopolicy/tests/audio_health_tests.cpp
@@ -111,16 +111,17 @@
             continue;
         }
         std::string address = "11:22:33:44:55:66";
+        media::AudioPort aidlPort;
+        ASSERT_EQ(OK, manager.deviceToAudioPort(device->type(), address.c_str(), "" /*name*/,
+                                                 &aidlPort));
         ASSERT_EQ(AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
                 AudioSystem::getDeviceConnectionState(device->type(), address.c_str()));
         ASSERT_EQ(NO_ERROR, AudioSystem::setDeviceConnectionState(
-                device->type(), AUDIO_POLICY_DEVICE_STATE_AVAILABLE, address.c_str(),
-                "" /*device_name*/, AUDIO_FORMAT_DEFAULT));
+                AUDIO_POLICY_DEVICE_STATE_AVAILABLE, aidlPort.hal, AUDIO_FORMAT_DEFAULT));
         ASSERT_EQ(AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
                 AudioSystem::getDeviceConnectionState(device->type(), address.c_str()));
         ASSERT_EQ(NO_ERROR, AudioSystem::setDeviceConnectionState(
-                device->type(), AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, address.c_str(),
-                "" /*device_name*/, AUDIO_FORMAT_DEFAULT));
+                AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, aidlPort.hal, AUDIO_FORMAT_DEFAULT));
         ASSERT_EQ(AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
                 AudioSystem::getDeviceConnectionState(device->type(), address.c_str()));
     }
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 9b0d0e7..efbae47 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -1763,7 +1763,7 @@
         bool isCompositeStream = false;
         for (const auto& gbp : mConfiguredOutputs.valueAt(index).getGraphicBufferProducers()) {
             sp<Surface> s = new Surface(gbp, false /*controlledByApp*/);
-            isCompositeStream = camera3::DepthCompositeStream::isDepthCompositeStream(s) |
+            isCompositeStream = camera3::DepthCompositeStream::isDepthCompositeStream(s) ||
                 camera3::HeicCompositeStream::isHeicCompositeStream(s);
             if (isCompositeStream) {
                 auto compositeIdx = mCompositeStreamMap.indexOfKey(IInterface::asBinder(gbp));
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 69723b6..98cbbcf 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -581,7 +581,7 @@
     mHandoutTotalBufferCount = 0;
     mFrameCount = 0;
     mLastTimestamp = 0;
-    mUseMonoTimestamp = (isConsumedByHWComposer() | isVideoStream());
+    mUseMonoTimestamp = (isConsumedByHWComposer() || isVideoStream());
 
     res = native_window_set_buffer_count(mConsumer.get(),
             mTotalBufferCount);
diff --git a/services/mediaresourcemanager/IMediaResourceMonitor.h b/services/mediaresourcemanager/IMediaResourceMonitor.h
index f92d557..4dd87e1 100644
--- a/services/mediaresourcemanager/IMediaResourceMonitor.h
+++ b/services/mediaresourcemanager/IMediaResourceMonitor.h
@@ -32,6 +32,7 @@
     enum {
         TYPE_VIDEO_CODEC = 0,
         TYPE_AUDIO_CODEC = 1,
+        TYPE_IMAGE_CODEC = 2,
     };
 
     virtual void notifyResourceGranted(/*in*/ int32_t pid, /*in*/ const int32_t type) = 0;
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index 953686b..d50f8d5 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -51,8 +51,8 @@
 
 class DeathNotifier : public RefBase {
 public:
-    DeathNotifier(const std::shared_ptr<ResourceManagerService> &service,
-            int pid, int64_t clientId);
+    DeathNotifier(const std::shared_ptr<ResourceManagerService> &service, int pid,
+            int64_t clientId);
 
     virtual ~DeathNotifier() {}
 
@@ -130,27 +130,48 @@
     return itemsStr;
 }
 
-static bool hasResourceType(MediaResource::Type type, const ResourceList& resources) {
+static bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
+        MediaResourceParcel resource) {
+    if (type != resource.type) {
+      return false;
+    }
+    switch (type) {
+        // Codec subtypes (e.g. video vs. audio) are each considered separate resources, so
+        // compare the subtypes as well.
+        case MediaResource::Type::kSecureCodec:
+        case MediaResource::Type::kNonSecureCodec:
+            if (resource.subType == subType) {
+                return true;
+            }
+            break;
+        // Non-codec resources are not segregated by the subtype (e.g. video vs. audio).
+        default:
+            return true;
+    }
+    return false;
+}
+
+static bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
+        const ResourceList& resources) {
     for (auto it = resources.begin(); it != resources.end(); it++) {
-        if (it->second.type == type) {
+        if (hasResourceType(type, subType, it->second)) {
             return true;
         }
     }
     return false;
 }
 
-static bool hasResourceType(MediaResource::Type type, const ResourceInfos& infos) {
+static bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
+        const ResourceInfos& infos) {
     for (size_t i = 0; i < infos.size(); ++i) {
-        if (hasResourceType(type, infos[i].resources)) {
+        if (hasResourceType(type, subType, infos[i].resources)) {
             return true;
         }
     }
     return false;
 }
 
-static ResourceInfos& getResourceInfosForEdit(
-        int pid,
-        PidResourceInfosMap& map) {
+static ResourceInfos& getResourceInfosForEdit(int pid, PidResourceInfosMap& map) {
     ssize_t index = map.indexOfKey(pid);
     if (index < 0) {
         // new pid
@@ -161,11 +182,8 @@
     return map.editValueFor(pid);
 }
 
-static ResourceInfo& getResourceInfoForEdit(
-        uid_t uid,
-        int64_t clientId,
-        const std::shared_ptr<IResourceManagerClient>& client,
-        ResourceInfos& infos) {
+static ResourceInfo& getResourceInfoForEdit(uid_t uid, int64_t clientId,
+        const std::shared_ptr<IResourceManagerClient>& client, ResourceInfos& infos) {
     ssize_t index = infos.indexOfKey(clientId);
 
     if (index < 0) {
@@ -188,17 +206,24 @@
     if (binder != NULL) {
         sp<IMediaResourceMonitor> service = interface_cast<IMediaResourceMonitor>(binder);
         for (size_t i = 0; i < resources.size(); ++i) {
-            if (resources[i].subType == MediaResource::SubType::kAudioCodec) {
-                service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_AUDIO_CODEC);
-            } else if (resources[i].subType == MediaResource::SubType::kVideoCodec) {
-                service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_VIDEO_CODEC);
+            switch (resources[i].subType) {
+                case MediaResource::SubType::kAudioCodec:
+                    service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_AUDIO_CODEC);
+                    break;
+                case MediaResource::SubType::kVideoCodec:
+                    service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_VIDEO_CODEC);
+                    break;
+                case MediaResource::SubType::kImageCodec:
+                    service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_IMAGE_CODEC);
+                    break;
+                case MediaResource::SubType::kUnspecifiedSubType:
+                    break;
             }
         }
     }
 }
 
-binder_status_t ResourceManagerService::dump(
-        int fd, const char** /*args*/, uint32_t /*numArgs*/) {
+binder_status_t ResourceManagerService::dump(int fd, const char** /*args*/, uint32_t /*numArgs*/) {
     String8 result;
 
     if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
@@ -275,8 +300,7 @@
     return OK;
 }
 
-struct SystemCallbackImpl :
-        public ResourceManagerService::SystemCallbackInterface {
+struct SystemCallbackImpl : public ResourceManagerService::SystemCallbackInterface {
     SystemCallbackImpl() : mClientToken(new BBinder()) {}
 
     virtual void noteStartVideo(int uid) override {
@@ -303,8 +327,7 @@
 ResourceManagerService::ResourceManagerService()
     : ResourceManagerService(new ProcessInfo(), new SystemCallbackImpl()) {}
 
-ResourceManagerService::ResourceManagerService(
-        const sp<ProcessInfoInterface> &processInfo,
+ResourceManagerService::ResourceManagerService(const sp<ProcessInfoInterface> &processInfo,
         const sp<SystemCallbackInterface> &systemResource)
     : mProcessInfo(processInfo),
       mSystemCB(systemResource),
@@ -362,8 +385,8 @@
     return Status::ok();
 }
 
-void ResourceManagerService::onFirstAdded(
-        const MediaResourceParcel& resource, const ResourceInfo& clientInfo) {
+void ResourceManagerService::onFirstAdded(const MediaResourceParcel& resource,
+        const ResourceInfo& clientInfo) {
     // first time added
     if (resource.type == MediaResource::Type::kCpuBoost
      && resource.subType == MediaResource::SubType::kUnspecifiedSubType) {
@@ -380,8 +403,8 @@
     }
 }
 
-void ResourceManagerService::onLastRemoved(
-        const MediaResourceParcel& resource, const ResourceInfo& clientInfo) {
+void ResourceManagerService::onLastRemoved(const MediaResourceParcel& resource,
+        const ResourceInfo& clientInfo) {
     if (resource.type == MediaResource::Type::kCpuBoost
             && resource.subType == MediaResource::SubType::kUnspecifiedSubType
             && mCpuBoostCount > 0) {
@@ -394,8 +417,8 @@
     }
 }
 
-void ResourceManagerService::mergeResources(
-        MediaResourceParcel& r1, const MediaResourceParcel& r2) {
+void ResourceManagerService::mergeResources(MediaResourceParcel& r1,
+        const MediaResourceParcel& r2) {
     // The resource entry on record is maintained to be in [0,INT64_MAX].
     // Clamp if merging in the new resource value causes it to go out of bound.
     // Note that the new resource value could be negative, eg.DrmSession, the
@@ -411,10 +434,7 @@
     }
 }
 
-Status ResourceManagerService::addResource(
-        int32_t pid,
-        int32_t uid,
-        int64_t clientId,
+Status ResourceManagerService::addResource(int32_t pid, int32_t uid, int64_t clientId,
         const std::shared_ptr<IResourceManagerClient>& client,
         const std::vector<MediaResourceParcel>& resources) {
     String8 log = String8::format("addResource(pid %d, clientId %lld, resources %s)",
@@ -473,8 +493,7 @@
     return Status::ok();
 }
 
-Status ResourceManagerService::removeResource(
-        int32_t pid, int64_t clientId,
+Status ResourceManagerService::removeResource(int32_t pid, int64_t clientId,
         const std::vector<MediaResourceParcel>& resources) {
     String8 log = String8::format("removeResource(pid %d, clientId %lld, resources %s)",
             pid, (long long) clientId, getString(resources).string());
@@ -583,22 +602,19 @@
     return Status::ok();
 }
 
-void ResourceManagerService::getClientForResource_l(
-        int callingPid, const MediaResourceParcel *res,
+void ResourceManagerService::getClientForResource_l(int callingPid, const MediaResourceParcel *res,
         Vector<std::shared_ptr<IResourceManagerClient>> *clients) {
     if (res == NULL) {
         return;
     }
     std::shared_ptr<IResourceManagerClient> client;
-    if (getLowestPriorityBiggestClient_l(callingPid, res->type, &client)) {
+    if (getLowestPriorityBiggestClient_l(callingPid, res->type, res->subType, &client)) {
         clients->push_back(client);
     }
 }
 
-Status ResourceManagerService::reclaimResource(
-        int32_t callingPid,
-        const std::vector<MediaResourceParcel>& resources,
-        bool* _aidl_return) {
+Status ResourceManagerService::reclaimResource(int32_t callingPid,
+        const std::vector<MediaResourceParcel>& resources, bool* _aidl_return) {
     String8 log = String8::format("reclaimResource(callingPid %d, resources %s)",
             callingPid, getString(resources).string());
     mServiceLog->add(log);
@@ -618,34 +634,43 @@
         const MediaResourceParcel *graphicMemory = NULL;
         const MediaResourceParcel *drmSession = NULL;
         for (size_t i = 0; i < resources.size(); ++i) {
-            MediaResource::Type type = resources[i].type;
-            if (resources[i].type == MediaResource::Type::kSecureCodec) {
-                secureCodec = &resources[i];
-            } else if (type == MediaResource::Type::kNonSecureCodec) {
-                nonSecureCodec = &resources[i];
-            } else if (type == MediaResource::Type::kGraphicMemory) {
-                graphicMemory = &resources[i];
-            } else if (type == MediaResource::Type::kDrmSession) {
-                drmSession = &resources[i];
+            switch (resources[i].type) {
+                case MediaResource::Type::kSecureCodec:
+                    secureCodec = &resources[i];
+                    break;
+                case MediaResource::Type::kNonSecureCodec:
+                    nonSecureCodec = &resources[i];
+                    break;
+                case MediaResource::Type::kGraphicMemory:
+                    graphicMemory = &resources[i];
+                    break;
+                case MediaResource::Type::kDrmSession:
+                    drmSession = &resources[i];
+                    break;
+                default:
+                    break;
             }
         }
 
         // first pass to handle secure/non-secure codec conflict
         if (secureCodec != NULL) {
             if (!mSupportsMultipleSecureCodecs) {
-                if (!getAllClients_l(callingPid, MediaResource::Type::kSecureCodec, &clients)) {
+                if (!getAllClients_l(callingPid, MediaResource::Type::kSecureCodec,
+                            secureCodec->subType, &clients)) {
                     return Status::ok();
                 }
             }
             if (!mSupportsSecureWithNonSecureCodec) {
-                if (!getAllClients_l(callingPid, MediaResource::Type::kNonSecureCodec, &clients)) {
+                if (!getAllClients_l(callingPid, MediaResource::Type::kNonSecureCodec,
+                            secureCodec->subType, &clients)) {
                     return Status::ok();
                 }
             }
         }
         if (nonSecureCodec != NULL) {
             if (!mSupportsSecureWithNonSecureCodec) {
-                if (!getAllClients_l(callingPid, MediaResource::Type::kSecureCodec, &clients)) {
+                if (!getAllClients_l(callingPid, MediaResource::Type::kSecureCodec,
+                        nonSecureCodec->subType, &clients)) {
                     return Status::ok();
                 }
             }
@@ -681,11 +706,11 @@
         }
     }
 
-    *_aidl_return = reclaimInternal(clients);
+    *_aidl_return = reclaimUnconditionallyFrom(clients);
     return Status::ok();
 }
 
-bool ResourceManagerService::reclaimInternal(
+bool ResourceManagerService::reclaimUnconditionallyFrom(
         const Vector<std::shared_ptr<IResourceManagerClient>> &clients) {
     if (clients.size() == 0) {
         return false;
@@ -732,9 +757,7 @@
     return false;
 }
 
-Status ResourceManagerService::overridePid(
-        int originalPid,
-        int newPid) {
+Status ResourceManagerService::overridePid(int originalPid, int newPid) {
     String8 log = String8::format("overridePid(originalPid %d, newPid %d)",
             originalPid, newPid);
     mServiceLog->add(log);
@@ -763,9 +786,7 @@
 }
 
 Status ResourceManagerService::overrideProcessInfo(
-        const std::shared_ptr<IResourceManagerClient>& client,
-        int pid,
-        int procState,
+        const std::shared_ptr<IResourceManagerClient>& client, int pid, int procState,
         int oomScore) {
     String8 log = String8::format("overrideProcessInfo(pid %d, procState %d, oomScore %d)",
             pid, procState, oomScore);
@@ -799,8 +820,8 @@
     return Status::ok();
 }
 
-uintptr_t ResourceManagerService::addCookieAndLink_l(
-        ::ndk::SpAIBinder binder, const sp<DeathNotifier>& notifier) {
+uintptr_t ResourceManagerService::addCookieAndLink_l(::ndk::SpAIBinder binder,
+        const sp<DeathNotifier>& notifier) {
     std::scoped_lock lock{sCookieLock};
 
     uintptr_t cookie;
@@ -813,8 +834,7 @@
     return cookie;
 }
 
-void ResourceManagerService::removeCookieAndUnlink_l(
-        ::ndk::SpAIBinder binder, uintptr_t cookie) {
+void ResourceManagerService::removeCookieAndUnlink_l(::ndk::SpAIBinder binder, uintptr_t cookie) {
     std::scoped_lock lock{sCookieLock};
     AIBinder_unlinkToDeath(binder.get(), mDeathRecipient.get(), (void*)cookie);
     sCookieToDeathNotifierMap.erase(cookie);
@@ -889,16 +909,34 @@
                                          MediaResource::Type::kNonSecureCodec,
                                          MediaResource::Type::kGraphicMemory,
                                          MediaResource::Type::kDrmSession}) {
-            std::shared_ptr<IResourceManagerClient> client;
-            if (getBiggestClient_l(pid, type, &client, true /* pendingRemovalOnly */)) {
-                clients.add(client);
-                break;
+            switch (type) {
+                // Codec resources are segregated by audio, video and image domains.
+                case MediaResource::Type::kSecureCodec:
+                case MediaResource::Type::kNonSecureCodec:
+                    for (MediaResource::SubType subType : {MediaResource::SubType::kAudioCodec,
+                                                           MediaResource::SubType::kVideoCodec,
+                                                           MediaResource::SubType::kImageCodec}) {
+                        std::shared_ptr<IResourceManagerClient> client;
+                        if (getBiggestClientPendingRemoval_l(pid, type, subType, &client)) {
+                            clients.add(client);
+                            continue;
+                        }
+                    }
+                    break;
+                // Non-codec resources are shared by audio, video and image codecs (no subtype).
+                default:
+                    std::shared_ptr<IResourceManagerClient> client;
+                    if (getBiggestClientPendingRemoval_l(pid, type,
+                            MediaResource::SubType::kUnspecifiedSubType, &client)) {
+                        clients.add(client);
+                    }
+                    break;
             }
         }
     }
 
     if (!clients.empty()) {
-        reclaimInternal(clients);
+        reclaimUnconditionallyFrom(clients);
     }
     return Status::ok();
 }
@@ -915,14 +953,13 @@
     return mProcessInfo->getPriority(newPid, priority);
 }
 
-bool ResourceManagerService::getAllClients_l(
-        int callingPid, MediaResource::Type type,
-        Vector<std::shared_ptr<IResourceManagerClient>> *clients) {
+bool ResourceManagerService::getAllClients_l(int callingPid, MediaResource::Type type,
+        MediaResource::SubType subType, Vector<std::shared_ptr<IResourceManagerClient>> *clients) {
     Vector<std::shared_ptr<IResourceManagerClient>> temp;
     for (size_t i = 0; i < mMap.size(); ++i) {
         ResourceInfos &infos = mMap.editValueAt(i);
         for (size_t j = 0; j < infos.size(); ++j) {
-            if (hasResourceType(type, infos[j].resources)) {
+            if (hasResourceType(type, subType, infos[j].resources)) {
                 if (!isCallingPriorityHigher_l(callingPid, mMap.keyAt(i))) {
                     // some higher/equal priority process owns the resource,
                     // this request can't be fulfilled.
@@ -942,8 +979,8 @@
     return true;
 }
 
-bool ResourceManagerService::getLowestPriorityBiggestClient_l(
-        int callingPid, MediaResource::Type type,
+bool ResourceManagerService::getLowestPriorityBiggestClient_l(int callingPid,
+        MediaResource::Type type, MediaResource::SubType subType,
         std::shared_ptr<IResourceManagerClient> *client) {
     int lowestPriorityPid;
     int lowestPriority;
@@ -951,7 +988,7 @@
 
     // 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 */)) {
+    if (getBiggestClientPendingRemoval_l(callingPid, type, subType, client)) {
         return true;
     }
     if (!getPriority_l(callingPid, &callingPriority)) {
@@ -959,7 +996,7 @@
                 callingPid);
         return false;
     }
-    if (!getLowestPriorityPid_l(type, &lowestPriorityPid, &lowestPriority)) {
+    if (!getLowestPriorityPid_l(type, subType, &lowestPriorityPid, &lowestPriority)) {
         return false;
     }
     if (lowestPriority <= callingPriority) {
@@ -968,14 +1005,14 @@
         return false;
     }
 
-    if (!getBiggestClient_l(lowestPriorityPid, type, client)) {
+    if (!getBiggestClient_l(lowestPriorityPid, type, subType, client)) {
         return false;
     }
     return true;
 }
 
-bool ResourceManagerService::getLowestPriorityPid_l(
-        MediaResource::Type type, int *lowestPriorityPid, int *lowestPriority) {
+bool ResourceManagerService::getLowestPriorityPid_l(MediaResource::Type type,
+        MediaResource::SubType subType, int *lowestPriorityPid, int *lowestPriority) {
     int pid = -1;
     int priority = -1;
     for (size_t i = 0; i < mMap.size(); ++i) {
@@ -983,7 +1020,7 @@
             // no client on this process.
             continue;
         }
-        if (!hasResourceType(type, mMap.valueAt(i))) {
+        if (!hasResourceType(type, subType, mMap.valueAt(i))) {
             // doesn't have the requested resource type
             continue;
         }
@@ -1021,8 +1058,13 @@
     return (callingPidPriority < priority);
 }
 
-bool ResourceManagerService::getBiggestClient_l(
-        int pid, MediaResource::Type type, std::shared_ptr<IResourceManagerClient> *client,
+bool ResourceManagerService::getBiggestClientPendingRemoval_l(int pid, MediaResource::Type type,
+        MediaResource::SubType subType, std::shared_ptr<IResourceManagerClient> *client) {
+    return getBiggestClient_l(pid, type, subType, client, true /* pendingRemovalOnly */);
+}
+
+bool ResourceManagerService::getBiggestClient_l(int pid, MediaResource::Type type,
+        MediaResource::SubType subType, std::shared_ptr<IResourceManagerClient> *client,
         bool pendingRemovalOnly) {
     ssize_t index = mMap.indexOfKey(pid);
     if (index < 0) {
@@ -1041,7 +1083,7 @@
         }
         for (auto it = resources.begin(); it != resources.end(); it++) {
             const MediaResourceParcel &resource = it->second;
-            if (resource.type == type) {
+            if (hasResourceType(type, subType, resource)) {
                 if (resource.value > largestValue) {
                     largestValue = resource.value;
                     clientTemp = infos[i].client;
@@ -1052,8 +1094,8 @@
 
     if (clientTemp == NULL) {
         ALOGE_IF(!pendingRemovalOnly,
-                 "getBiggestClient_l: can't find resource type %s for pid %d",
-                 asString(type), pid);
+                 "getBiggestClient_l: can't find resource type %s and subtype %s for pid %d",
+                 asString(type), asString(subType), pid);
         return false;
     }
 
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index 9c2636e..6551371 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -77,26 +77,19 @@
             int /*fd*/, const char** /*args*/, uint32_t /*numArgs*/);
 
     ResourceManagerService();
-    explicit ResourceManagerService(
-            const sp<ProcessInfoInterface> &processInfo,
+    explicit ResourceManagerService(const sp<ProcessInfoInterface> &processInfo,
             const sp<SystemCallbackInterface> &systemResource);
     virtual ~ResourceManagerService();
-    void setObserverService(
-            const std::shared_ptr<ResourceObserverService>& observerService);
+    void setObserverService(const std::shared_ptr<ResourceObserverService>& observerService);
 
     // IResourceManagerService interface
     Status config(const std::vector<MediaResourcePolicyParcel>& policies) override;
 
-    Status addResource(
-            int32_t pid,
-            int32_t uid,
-            int64_t clientId,
+    Status addResource(int32_t pid, int32_t uid, int64_t clientId,
             const std::shared_ptr<IResourceManagerClient>& client,
             const std::vector<MediaResourceParcel>& resources) override;
 
-    Status removeResource(
-            int32_t pid,
-            int64_t clientId,
+    Status removeResource(int32_t pid, int64_t clientId,
             const std::vector<MediaResourceParcel>& resources) override;
 
     Status removeClient(int32_t pid, int64_t clientId) override;
@@ -104,20 +97,13 @@
     // Tries to reclaim resource from processes with lower priority than the calling process
     // according to the requested resources.
     // Returns true if any resource has been reclaimed, otherwise returns false.
-    Status reclaimResource(
-            int32_t callingPid,
-            const std::vector<MediaResourceParcel>& resources,
+    Status reclaimResource(int32_t callingPid, const std::vector<MediaResourceParcel>& resources,
             bool* _aidl_return) override;
 
-    Status overridePid(
-            int originalPid,
-            int newPid) override;
+    Status overridePid(int originalPid, int newPid) override;
 
-    Status overrideProcessInfo(
-            const std::shared_ptr<IResourceManagerClient>& client,
-            int pid,
-            int procState,
-            int oomScore) override;
+    Status overrideProcessInfo(const std::shared_ptr<IResourceManagerClient>& client, int pid,
+            int procState, int oomScore) override;
 
     Status markClientForPendingRemoval(int32_t pid, int64_t clientId) override;
 
@@ -132,30 +118,34 @@
 
     // Reclaims resources from |clients|. Returns true if reclaim succeeded
     // for all clients.
-    bool reclaimInternal(
-            const Vector<std::shared_ptr<IResourceManagerClient>> &clients);
+    bool reclaimUnconditionallyFrom(const Vector<std::shared_ptr<IResourceManagerClient>> &clients);
 
     // Gets the list of all the clients who own the specified resource type.
     // Returns false if any client belongs to a process with higher priority than the
     // calling process. The clients will remain unchanged if returns false.
-    bool getAllClients_l(int callingPid, MediaResource::Type type,
+    bool getAllClients_l(int callingPid, MediaResource::Type type, MediaResource::SubType subType,
             Vector<std::shared_ptr<IResourceManagerClient>> *clients);
 
     // Gets the client who owns specified resource type from lowest possible priority process.
     // Returns false if the calling process priority is not higher than the lowest process
     // priority. The client will remain unchanged if returns false.
     bool getLowestPriorityBiggestClient_l(int callingPid, MediaResource::Type type,
-            std::shared_ptr<IResourceManagerClient> *client);
+            MediaResource::SubType subType, std::shared_ptr<IResourceManagerClient> *client);
 
     // Gets lowest priority process that has the specified resource type.
     // Returns false if failed. The output parameters will remain unchanged if failed.
-    bool getLowestPriorityPid_l(MediaResource::Type type, int *pid, int *priority);
+    bool getLowestPriorityPid_l(MediaResource::Type type, MediaResource::SubType subType, int *pid,
+                int *priority);
 
     // 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,
+    // Returns false with no change to client if there are no clients holdiing resources of thisi
+    // type.
+    bool getBiggestClient_l(int pid, MediaResource::Type type, MediaResource::SubType subType,
             std::shared_ptr<IResourceManagerClient> *client,
             bool pendingRemovalOnly = false);
+    // Same method as above, but with pendingRemovalOnly as true.
+    bool getBiggestClientPendingRemoval_l(int pid, MediaResource::Type type,
+            MediaResource::SubType subType, std::shared_ptr<IResourceManagerClient> *client);
 
     bool isCallingPriorityHigher_l(int callingPid, int pid);
 
diff --git a/services/mediaresourcemanager/aidl/android/media/MediaResourceSubType.aidl b/services/mediaresourcemanager/aidl/android/media/MediaResourceSubType.aidl
index af2ba68..72a0551 100644
--- a/services/mediaresourcemanager/aidl/android/media/MediaResourceSubType.aidl
+++ b/services/mediaresourcemanager/aidl/android/media/MediaResourceSubType.aidl
@@ -26,4 +26,5 @@
     kUnspecifiedSubType = 0,
     kAudioCodec = 1,
     kVideoCodec = 2,
+    kImageCodec = 3,
 }
diff --git a/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h b/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
index 8e29312..1624477 100644
--- a/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
+++ b/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
@@ -119,11 +119,11 @@
 
 struct TestClient : public BnResourceManagerClient {
     TestClient(int pid, const std::shared_ptr<ResourceManagerService> &service)
-        : mReclaimed(false), mPid(pid), mService(service) {}
+        : mPid(pid), mService(service) {}
 
     Status reclaimResource(bool* _aidl_return) override {
         mService->removeClient(mPid, getId(ref<TestClient>()));
-        mReclaimed = true;
+        mWasReclaimResourceCalled = true;
         *_aidl_return = true;
         return Status::ok();
     }
@@ -133,18 +133,16 @@
         return Status::ok();
     }
 
-    bool reclaimed() const {
-        return mReclaimed;
-    }
-
-    void reset() {
-        mReclaimed = false;
+    bool checkIfReclaimedAndReset() {
+        bool wasReclaimResourceCalled = mWasReclaimResourceCalled;
+        mWasReclaimResourceCalled = false;
+        return wasReclaimResourceCalled;
     }
 
     virtual ~TestClient() {}
 
 private:
-    bool mReclaimed;
+    bool mWasReclaimResourceCalled = false;
     int mPid;
     std::shared_ptr<ResourceManagerService> mService;
     DISALLOW_EVIL_CONSTRUCTORS(TestClient);
@@ -166,14 +164,30 @@
     return lhs.type == rhs.type && lhs.arg == rhs.arg;
 }
 
-#define CHECK_STATUS_TRUE(condition) \
-    EXPECT_TRUE((condition).isOk() && (result))
+// The condition is expected to return a status but also update the local
+// result variable.
+#define CHECK_STATUS_TRUE(conditionThatUpdatesResult) \
+    do { \
+        bool result = false; \
+        EXPECT_TRUE((conditionThatUpdatesResult).isOk()); \
+        EXPECT_TRUE(result); \
+    } while(false)
 
-#define CHECK_STATUS_FALSE(condition) \
-    EXPECT_TRUE((condition).isOk() && !(result))
+// The condition is expected to return a status but also update the local
+// result variable.
+#define CHECK_STATUS_FALSE(conditionThatUpdatesResult) \
+    do { \
+        bool result = true; \
+        EXPECT_TRUE((conditionThatUpdatesResult).isOk()); \
+        EXPECT_FALSE(result); \
+    } while(false)
 
 class ResourceManagerServiceTestBase : public ::testing::Test {
 public:
+    static TestClient* toTestClient(std::shared_ptr<IResourceManagerClient> testClient) {
+        return static_cast<TestClient*>(testClient.get());
+    }
+
     ResourceManagerServiceTestBase()
         : mSystemCB(new TestSystemCallback()),
           mService(::ndk::SharedRefBase::make<ResourceManagerService>(
@@ -183,6 +197,10 @@
           mTestClient3(::ndk::SharedRefBase::make<TestClient>(kTestPid2, mService)) {
     }
 
+    std::shared_ptr<IResourceManagerClient> createTestClient(int pid) {
+        return ::ndk::SharedRefBase::make<TestClient>(pid, mService);
+    }
+
     sp<TestSystemCallback> mSystemCB;
     std::shared_ptr<ResourceManagerService> mService;
     std::shared_ptr<IResourceManagerClient> mTestClient1;
diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
index a029d45..8739c3b 100644
--- a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
@@ -25,22 +25,60 @@
 namespace android {
 
 class ResourceManagerServiceTest : public ResourceManagerServiceTestBase {
+private:
+    static MediaResource createSecureVideoCodecResource(int amount = 1) {
+        return MediaResource(MediaResource::Type::kSecureCodec,
+            MediaResource::SubType::kVideoCodec, amount);
+    }
+
+    static MediaResource createNonSecureVideoCodecResource(int amount = 1) {
+        return MediaResource(MediaResource::Type::kNonSecureCodec,
+            MediaResource::SubType::kVideoCodec, amount);
+    }
+
+    static MediaResource createSecureAudioCodecResource(int amount = 1) {
+        return MediaResource(MediaResource::Type::kSecureCodec,
+            MediaResource::SubType::kAudioCodec, amount);
+    }
+
+    static MediaResource createNonSecureAudioCodecResource(int amount = 1) {
+        return MediaResource(MediaResource::Type::kNonSecureCodec,
+            MediaResource::SubType::kAudioCodec, amount);
+    }
+
+    static MediaResource createSecureImageCodecResource(int amount = 1) {
+        return MediaResource(MediaResource::Type::kSecureCodec,
+            MediaResource::SubType::kImageCodec, amount);
+    }
+
+    static MediaResource createNonSecureImageCodecResource(int amount = 1) {
+        return MediaResource(MediaResource::Type::kNonSecureCodec,
+            MediaResource::SubType::kImageCodec, amount);
+    }
+
+    static MediaResource createGraphicMemoryResource(int amount = 1) {
+        return MediaResource(MediaResource::Type::kGraphicMemory,
+            MediaResource::SubType::kUnspecifiedSubType, amount);
+    }
+
+    static MediaResource createDrmSessionResource(int amount = 1) {
+        return MediaResource(MediaResource::Type::kDrmSession,
+            MediaResource::SubType::kUnspecifiedSubType, amount);
+    }
+
+    static MediaResource createBatteryResource() {
+        return MediaResource(MediaResource::Type::kBattery,
+            MediaResource::SubType::kUnspecifiedSubType, 1);
+    }
+
+    static MediaResource createCpuBoostResource() {
+        return MediaResource(MediaResource::Type::kCpuBoost,
+            MediaResource::SubType::kUnspecifiedSubType, 1);
+    }
+
 public:
     ResourceManagerServiceTest() : ResourceManagerServiceTestBase() {}
 
-    void verifyClients(bool c1, bool c2, bool c3) {
-        TestClient *client1 = static_cast<TestClient*>(mTestClient1.get());
-        TestClient *client2 = static_cast<TestClient*>(mTestClient2.get());
-        TestClient *client3 = static_cast<TestClient*>(mTestClient3.get());
-
-        EXPECT_EQ(c1, client1->reclaimed());
-        EXPECT_EQ(c2, client2->reclaimed());
-        EXPECT_EQ(c3, client3->reclaimed());
-
-        client1->reset();
-        client2->reset();
-        client3->reset();
-    }
 
     // test set up
     // ---------------------------------------------------------------------------------
@@ -268,7 +306,6 @@
 
     void testOverridePid() {
 
-        bool result;
         std::vector<MediaResourceParcel> resources;
         resources.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
         resources.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 150));
@@ -293,8 +330,6 @@
     }
 
     void testMarkClientForPendingRemoval() {
-        bool result;
-
         {
             addResource();
             mService->mSupportsSecureWithNonSecureCodec = true;
@@ -307,13 +342,17 @@
 
             // no lower priority client
             CHECK_STATUS_FALSE(mService->reclaimResource(kTestPid2, resources, &result));
-            verifyClients(false /* c1 */, false /* c2 */, false /* c3 */);
+            EXPECT_EQ(false, toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+            EXPECT_EQ(false, toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+            EXPECT_EQ(false, toTestClient(mTestClient3)->checkIfReclaimedAndReset());
 
             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 */);
+            EXPECT_EQ(false, toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+            EXPECT_EQ(true, toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+            EXPECT_EQ(false, toTestClient(mTestClient3)->checkIfReclaimedAndReset());
 
             // clean up client 3 which still left
             mService->removeClient(kTestPid2, getId(mTestClient3));
@@ -331,11 +370,15 @@
             // 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 */);
+            EXPECT_EQ(false, toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+            EXPECT_EQ(true, toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+            EXPECT_EQ(false, toTestClient(mTestClient3)->checkIfReclaimedAndReset());
 
             // lower priority client got reclaimed
             CHECK_STATUS_TRUE(mService->reclaimResource(kTestPid2, resources, &result));
-            verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
+            EXPECT_EQ(true, toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+            EXPECT_EQ(false, toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+            EXPECT_EQ(false, toTestClient(mTestClient3)->checkIfReclaimedAndReset());
 
             // clean up client 3 which still left
             mService->removeClient(kTestPid2, getId(mTestClient3));
@@ -349,17 +392,23 @@
 
             // client marked for pending removal got reclaimed
             EXPECT_TRUE(mService->reclaimResourcesFromClientsPendingRemoval(kTestPid2).isOk());
-            verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
+            EXPECT_EQ(false, toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+            EXPECT_EQ(true, toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+            EXPECT_EQ(false, toTestClient(mTestClient3)->checkIfReclaimedAndReset());
 
             // No more clients marked for removal
             EXPECT_TRUE(mService->reclaimResourcesFromClientsPendingRemoval(kTestPid2).isOk());
-            verifyClients(false /* c1 */, false /* c2 */, false /* c3 */);
+            EXPECT_EQ(false, toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+            EXPECT_EQ(false, toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+            EXPECT_EQ(false, toTestClient(mTestClient3)->checkIfReclaimedAndReset());
 
             mService->markClientForPendingRemoval(kTestPid2, getId(mTestClient3));
 
             // client marked for pending removal got reclaimed
             EXPECT_TRUE(mService->reclaimResourcesFromClientsPendingRemoval(kTestPid2).isOk());
-            verifyClients(false /* c1 */, false /* c2 */, true /* c3 */);
+            EXPECT_EQ(false, toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+            EXPECT_EQ(false, toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+            EXPECT_EQ(true, toTestClient(mTestClient3)->checkIfReclaimedAndReset());
 
             // clean up client 1 which still left
             mService->removeClient(kTestPid1, getId(mTestClient1));
@@ -384,14 +433,15 @@
 
     void testGetAllClients() {
         addResource();
-
         MediaResource::Type type = MediaResource::Type::kSecureCodec;
+        MediaResource::SubType subType = MediaResource::SubType::kUnspecifiedSubType;
+
         Vector<std::shared_ptr<IResourceManagerClient> > clients;
-        EXPECT_FALSE(mService->getAllClients_l(kLowPriorityPid, type, &clients));
+        EXPECT_FALSE(mService->getAllClients_l(kLowPriorityPid, type, subType, &clients));
         // some higher priority process (e.g. kTestPid2) owns the resource, so getAllClients_l
         // will fail.
-        EXPECT_FALSE(mService->getAllClients_l(kMidPriorityPid, type, &clients));
-        EXPECT_TRUE(mService->getAllClients_l(kHighPriorityPid, type, &clients));
+        EXPECT_FALSE(mService->getAllClients_l(kMidPriorityPid, type, subType, &clients));
+        EXPECT_TRUE(mService->getAllClients_l(kHighPriorityPid, type, subType, &clients));
 
         EXPECT_EQ(2u, clients.size());
         // (OK to require ordering in clients[], as the pid map is sorted)
@@ -400,7 +450,6 @@
     }
 
     void testReclaimResourceSecure() {
-        bool result;
         std::vector<MediaResourceParcel> resources;
         resources.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
         resources.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 150));
@@ -417,11 +466,15 @@
 
             // reclaim all secure codecs
             CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
-            verifyClients(true /* c1 */, false /* c2 */, true /* c3 */);
+            EXPECT_TRUE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+            EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+            EXPECT_TRUE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
 
             // call again should reclaim one largest graphic memory from lowest process
             CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
-            verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
+            EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+            EXPECT_TRUE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+            EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
 
             // nothing left
             CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
@@ -439,7 +492,9 @@
 
             // reclaim all secure and non-secure codecs
             CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
-            verifyClients(true /* c1 */, true /* c2 */, true /* c3 */);
+            EXPECT_TRUE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+            EXPECT_TRUE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+            EXPECT_TRUE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
 
             // nothing left
             CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
@@ -458,15 +513,21 @@
 
             // reclaim all non-secure codecs
             CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
-            verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
+            EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+            EXPECT_TRUE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+            EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
 
             // call again should reclaim one largest graphic memory from lowest process
             CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
-            verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
+            EXPECT_TRUE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+            EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+            EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
 
             // call again should reclaim another largest graphic memory from lowest process
             CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
-            verifyClients(false /* c1 */, false /* c2 */, true /* c3 */);
+            EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+            EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+            EXPECT_TRUE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
 
             // nothing left
             CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
@@ -483,15 +544,21 @@
 
             CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
             // one largest graphic memory from lowest process got reclaimed
-            verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
+            EXPECT_TRUE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+            EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+            EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
 
             // call again should reclaim another graphic memory from lowest process
             CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
-            verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
+            EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+            EXPECT_TRUE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+            EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
 
             // call again should reclaim another graphic memory from lowest process
             CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
-            verifyClients(false /* c1 */, false /* c2 */, true /* c3 */);
+            EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+            EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+            EXPECT_TRUE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
 
             // nothing left
             CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
@@ -508,20 +575,25 @@
 
             CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
             // secure codec from lowest process got reclaimed
-            verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
+            EXPECT_TRUE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+            EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+            EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
 
             // call again should reclaim another secure codec from lowest process
             CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
-            verifyClients(false /* c1 */, false /* c2 */, true /* c3 */);
+            EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+            EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+            EXPECT_TRUE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
 
             // no more secure codec, non-secure codec will be reclaimed.
             CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
-            verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
+            EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+            EXPECT_TRUE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+            EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
         }
     }
 
     void testReclaimResourceNonSecure() {
-        bool result;
         std::vector<MediaResourceParcel> resources;
         resources.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
         resources.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 150));
@@ -537,11 +609,15 @@
 
             // reclaim all secure codecs
             CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
-            verifyClients(true /* c1 */, false /* c2 */, true /* c3 */);
+            EXPECT_TRUE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+            EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+            EXPECT_TRUE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
 
             // call again should reclaim one graphic memory from lowest process
             CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
-            verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
+            EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+            EXPECT_TRUE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+            EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
 
             // nothing left
             CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
@@ -558,15 +634,21 @@
 
             CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
             // one largest graphic memory from lowest process got reclaimed
-            verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
+            EXPECT_TRUE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+            EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+            EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
 
             // call again should reclaim another graphic memory from lowest process
             CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
-            verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
+            EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+            EXPECT_TRUE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+            EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
 
             // call again should reclaim another graphic memory from lowest process
             CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
-            verifyClients(false /* c1 */, false /* c2 */, true /* c3 */);
+            EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+            EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+            EXPECT_TRUE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
 
             // nothing left
             CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
@@ -582,11 +664,15 @@
 
             CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
             // one non secure codec from lowest process got reclaimed
-            verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
+            EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+            EXPECT_TRUE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+            EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
 
             // no more non-secure codec, secure codec from lowest priority process will be reclaimed
             CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
-            verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
+            EXPECT_TRUE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+            EXPECT_FALSE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+            EXPECT_FALSE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
 
             // clean up client 3 which still left
             mService->removeClient(kTestPid2, getId(mTestClient3));
@@ -595,13 +681,17 @@
 
     void testGetLowestPriorityBiggestClient() {
         MediaResource::Type type = MediaResource::Type::kGraphicMemory;
+        MediaResource::SubType subType = MediaResource::SubType::kUnspecifiedSubType;
         std::shared_ptr<IResourceManagerClient> client;
-        EXPECT_FALSE(mService->getLowestPriorityBiggestClient_l(kHighPriorityPid, type, &client));
+        EXPECT_FALSE(mService->getLowestPriorityBiggestClient_l(kHighPriorityPid, type, subType,
+                &client));
 
         addResource();
 
-        EXPECT_FALSE(mService->getLowestPriorityBiggestClient_l(kLowPriorityPid, type, &client));
-        EXPECT_TRUE(mService->getLowestPriorityBiggestClient_l(kHighPriorityPid, type, &client));
+        EXPECT_FALSE(mService->getLowestPriorityBiggestClient_l(kLowPriorityPid, type, subType,
+                &client));
+        EXPECT_TRUE(mService->getLowestPriorityBiggestClient_l(kHighPriorityPid, type, subType,
+                &client));
 
         // kTestPid1 is the lowest priority process with MediaResource::Type::kGraphicMemory.
         // mTestClient1 has the largest MediaResource::Type::kGraphicMemory within kTestPid1.
@@ -614,35 +704,25 @@
         TestProcessInfo processInfo;
 
         MediaResource::Type type = MediaResource::Type::kGraphicMemory;
-        EXPECT_FALSE(mService->getLowestPriorityPid_l(type, &pid, &priority));
+        MediaResource::SubType subType = MediaResource::SubType::kUnspecifiedSubType;
+        EXPECT_FALSE(mService->getLowestPriorityPid_l(type, subType, &pid, &priority));
 
         addResource();
 
-        EXPECT_TRUE(mService->getLowestPriorityPid_l(type, &pid, &priority));
+        EXPECT_TRUE(mService->getLowestPriorityPid_l(type, subType, &pid, &priority));
         EXPECT_EQ(kTestPid1, pid);
         int priority1;
         processInfo.getPriority(kTestPid1, &priority1);
         EXPECT_EQ(priority1, priority);
 
         type = MediaResource::Type::kNonSecureCodec;
-        EXPECT_TRUE(mService->getLowestPriorityPid_l(type, &pid, &priority));
+        EXPECT_TRUE(mService->getLowestPriorityPid_l(type, subType, &pid, &priority));
         EXPECT_EQ(kTestPid2, pid);
         int priority2;
         processInfo.getPriority(kTestPid2, &priority2);
         EXPECT_EQ(priority2, priority);
     }
 
-    void testGetBiggestClient() {
-        MediaResource::Type type = MediaResource::Type::kGraphicMemory;
-        std::shared_ptr<IResourceManagerClient> client;
-        EXPECT_FALSE(mService->getBiggestClient_l(kTestPid2, type, &client));
-
-        addResource();
-
-        EXPECT_TRUE(mService->getBiggestClient_l(kTestPid2, type, &client));
-        EXPECT_EQ(mTestClient2, client);
-    }
-
     void testIsCallingPriorityHigher() {
         EXPECT_FALSE(mService->isCallingPriorityHigher_l(101, 100));
         EXPECT_FALSE(mService->isCallingPriorityHigher_l(100, 100));
@@ -725,6 +805,361 @@
         EXPECT_EQ(4u, mSystemCB->eventCount());
         EXPECT_EQ(EventType::CPUSET_DISABLE, mSystemCB->lastEventType());
     }
+
+    void testReclaimResources_withVideoCodec_reclaimsOnlyVideoCodec() {
+        const std::shared_ptr<IResourceManagerClient>& audioImageTestClient = mTestClient1;
+        const std::shared_ptr<IResourceManagerClient>& videoTestClient = mTestClient2;
+
+        // Create an audio and image codec resource
+        std::vector<MediaResourceParcel> audioImageResources;
+        audioImageResources.push_back(createNonSecureAudioCodecResource());
+        audioImageResources.push_back(createNonSecureImageCodecResource());
+        mService->addResource(kLowPriorityPid, kTestUid1, getId(audioImageTestClient),
+                audioImageTestClient, audioImageResources);
+
+        // Fail to reclaim a video codec resource
+        std::vector<MediaResourceParcel> reclaimResources;
+        reclaimResources.push_back(createNonSecureVideoCodecResource());
+        CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, reclaimResources, &result));
+
+        // Now add a video codec resource
+        std::vector<MediaResourceParcel> videoResources;
+        videoResources.push_back(createNonSecureVideoCodecResource());
+        mService->addResource(kLowPriorityPid, kTestUid1, getId(videoTestClient), videoTestClient,
+                videoResources);
+
+        // Verify that the newly-created video codec resource can be reclaimed
+        CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, reclaimResources, &result));
+
+        // Verify that the audio and image resources are untouched
+        EXPECT_FALSE(toTestClient(audioImageTestClient)->checkIfReclaimedAndReset());
+        // But the video resource was reclaimed
+        EXPECT_TRUE(toTestClient(videoTestClient)->checkIfReclaimedAndReset());
+    }
+
+    void testReclaimResources_withAudioCodec_reclaimsOnlyAudioCodec() {
+        const auto & videoImageTestClient = mTestClient1;
+        const auto & audioTestClient = mTestClient2;
+
+        // Create a video and audio codec resource
+        std::vector<MediaResourceParcel> videoImageResources;
+        videoImageResources.push_back(createNonSecureVideoCodecResource());
+        videoImageResources.push_back(createNonSecureImageCodecResource());
+        mService->addResource(kLowPriorityPid, kTestUid1, getId(videoImageTestClient),
+                videoImageTestClient, videoImageResources);
+
+        // Fail to reclaim an audio codec resource
+        std::vector<MediaResourceParcel> reclaimResources;
+        reclaimResources.push_back(createNonSecureAudioCodecResource());
+        CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, reclaimResources, &result));
+
+        // Now add an audio codec resource
+        std::vector<MediaResourceParcel> audioResources;
+        audioResources.push_back(createNonSecureAudioCodecResource());
+        mService->addResource(kLowPriorityPid, kTestUid2, getId(audioTestClient), audioTestClient,
+                audioResources);
+
+        // Verify that the newly-created audio codec resource can be reclaimed
+        CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, reclaimResources, &result));
+
+        // Verify that the video and image resources are untouched
+        EXPECT_FALSE(toTestClient(videoImageTestClient)->checkIfReclaimedAndReset());
+        // But the audio resource was reclaimed
+        EXPECT_TRUE(toTestClient(audioTestClient)->checkIfReclaimedAndReset());
+    }
+
+    void testReclaimResources_withImageCodec_reclaimsOnlyImageCodec() {
+        const auto & videoAudioTestClient = mTestClient1;
+        const auto & imageTestClient = mTestClient2;
+
+        // Create a video and audio codec resource
+        std::vector<MediaResourceParcel> videoAudioResources;
+        videoAudioResources.push_back(createNonSecureVideoCodecResource());
+        videoAudioResources.push_back(createNonSecureAudioCodecResource());
+        mService->addResource(kLowPriorityPid, kTestUid1, getId(videoAudioTestClient),
+                videoAudioTestClient, videoAudioResources);
+
+        // Fail to reclaim an image codec resource
+        std::vector<MediaResourceParcel> reclaimResources;
+        reclaimResources.push_back(createNonSecureImageCodecResource());
+        CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, reclaimResources, &result));
+
+        // Now add an image codec resource
+        std::vector<MediaResourceParcel> imageResources;
+        imageResources.push_back(createNonSecureImageCodecResource());
+        mService->addResource(kLowPriorityPid, kTestUid2, getId(imageTestClient), imageTestClient,
+                imageResources);
+
+        // Verify that the newly-created image codec resource can be reclaimed
+        CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, reclaimResources, &result));
+
+        // Verify that the video and audio resources are untouched
+        EXPECT_FALSE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+        // But the image resource was reclaimed
+        EXPECT_TRUE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+    }
+
+    void testReclaimResources_whenPartialResourceMatch_reclaims() {
+        const int onlyUid = kTestUid1;
+        const auto onlyClient = createTestClient(kLowPriorityPid);
+
+        std::vector<MediaResourceParcel> ownedResources;
+        ownedResources.push_back(createNonSecureVideoCodecResource());
+        ownedResources.push_back(createGraphicMemoryResource(100));
+        mService->addResource(kLowPriorityPid, onlyUid, getId(onlyClient), onlyClient,
+                ownedResources);
+
+        // Reclaim an image codec instead of the video codec that is owned, but also reclaim
+        // graphics memory, which will trigger the reclaim.
+        std::vector<MediaResourceParcel> reclaimResources;
+        reclaimResources.push_back(createNonSecureImageCodecResource());
+        reclaimResources.push_back(createGraphicMemoryResource(100));
+        CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, reclaimResources, &result));
+
+        // Verify that the video codec resources (including the needed graphic memory) is reclaimed
+        EXPECT_TRUE(toTestClient(onlyClient)->checkIfReclaimedAndReset());
+    }
+
+    void testReclaimResourcesFromMarkedClients_removesBiggestMarkedClientForSomeResources() {
+        // this test only uses one pid and one uid
+        const int onlyPid = kTestPid1;
+        const int onlyUid = kTestUid1;
+
+        // secure video codec
+        const auto smallSecureVideoMarkedClient = createTestClient(onlyPid);
+        const auto largeSecureVideoMarkedClient = createTestClient(onlyPid);
+        const auto largestSecureVideoActiveClient = createTestClient(onlyPid);
+        {
+            std::vector<MediaResourceParcel> resources;
+            resources.push_back(createSecureVideoCodecResource(1));
+            mService->addResource(onlyPid, onlyUid, getId(smallSecureVideoMarkedClient),
+                    smallSecureVideoMarkedClient, resources);
+            resources.clear();
+            resources.push_back(createSecureVideoCodecResource(2));
+            mService->addResource(onlyPid, onlyUid, getId(largeSecureVideoMarkedClient),
+                    largeSecureVideoMarkedClient, resources);
+            resources.clear();
+            resources.push_back(createSecureVideoCodecResource(3));
+            mService->addResource(onlyPid, onlyUid, getId(largestSecureVideoActiveClient),
+                    largestSecureVideoActiveClient, resources);
+        }
+        mService->markClientForPendingRemoval(onlyPid, getId(smallSecureVideoMarkedClient));
+        mService->markClientForPendingRemoval(onlyPid, getId(largeSecureVideoMarkedClient));
+        // don't mark the largest client
+
+        // non-secure video codec
+        const auto smallNonSecureVideoMarkedClient = createTestClient(onlyPid);
+        const auto largeNonSecureVideoMarkedClient = createTestClient(onlyPid);
+        const auto largestNonSecureVideoActiveClient = createTestClient(onlyPid);
+        {
+            std::vector<MediaResourceParcel> resources;
+            resources.push_back(createNonSecureVideoCodecResource(1));
+            mService->addResource(onlyPid, onlyUid, getId(smallNonSecureVideoMarkedClient),
+                    smallNonSecureVideoMarkedClient, resources);
+            resources.clear();
+            resources.push_back(createNonSecureVideoCodecResource(2));
+            mService->addResource(onlyPid, onlyUid, getId(largeNonSecureVideoMarkedClient),
+                    largeNonSecureVideoMarkedClient, resources);
+            resources.clear();
+            resources.push_back(createNonSecureVideoCodecResource(3));
+            mService->addResource(onlyPid, onlyUid, getId(largestNonSecureVideoActiveClient),
+                    largestNonSecureVideoActiveClient, resources);
+        }
+        mService->markClientForPendingRemoval(onlyPid, getId(smallNonSecureVideoMarkedClient));
+        mService->markClientForPendingRemoval(onlyPid, getId(largeNonSecureVideoMarkedClient));
+        // don't mark the largest client
+
+        // secure audio codec
+        const auto smallSecureAudioMarkedClient = createTestClient(onlyPid);
+        const auto largeSecureAudioMarkedClient = createTestClient(onlyPid);
+        const auto largestSecureAudioActiveClient = createTestClient(onlyPid);
+        {
+            std::vector<MediaResourceParcel> resources;
+            resources.push_back(createSecureAudioCodecResource(1));
+            mService->addResource(onlyPid, onlyUid, getId(smallSecureAudioMarkedClient),
+                    smallSecureAudioMarkedClient, resources);
+            resources.clear();
+            resources.push_back(createSecureAudioCodecResource(2));
+            mService->addResource(onlyPid, onlyUid, getId(largeSecureAudioMarkedClient),
+                    largeSecureAudioMarkedClient, resources);
+            resources.clear();
+            resources.push_back(createSecureAudioCodecResource(3));
+            mService->addResource(onlyPid, onlyUid, getId(largestSecureVideoActiveClient),
+                    largestSecureVideoActiveClient, resources);
+        }
+        mService->markClientForPendingRemoval(onlyPid, getId(smallSecureAudioMarkedClient));
+        mService->markClientForPendingRemoval(onlyPid, getId(largeSecureAudioMarkedClient));
+        // don't mark the largest client
+
+        // non-secure audio codec
+        const auto smallNonSecureAudioMarkedClient = createTestClient(onlyPid);
+        const auto largeNonSecureAudioMarkedClient = createTestClient(onlyPid);
+        const auto largestNonSecureAudioActiveClient = createTestClient(onlyPid);
+        {
+            std::vector<MediaResourceParcel> resources;
+            resources.push_back(createNonSecureAudioCodecResource(1));
+            mService->addResource(onlyPid, onlyUid, getId(smallNonSecureAudioMarkedClient),
+                    smallNonSecureAudioMarkedClient, resources);
+            resources.clear();
+            resources.push_back(createNonSecureAudioCodecResource(2));
+            mService->addResource(onlyPid, onlyUid, getId(largeNonSecureAudioMarkedClient),
+                    largeNonSecureAudioMarkedClient, resources);
+            resources.clear();
+            resources.push_back(createNonSecureAudioCodecResource(3));
+            mService->addResource(onlyPid, onlyUid, getId(largestNonSecureAudioActiveClient),
+                    largestNonSecureAudioActiveClient, resources);
+        }
+        mService->markClientForPendingRemoval(onlyPid, getId(smallNonSecureAudioMarkedClient));
+        mService->markClientForPendingRemoval(onlyPid, getId(largeNonSecureAudioMarkedClient));
+        // don't mark the largest client
+
+        // secure image codec
+        const auto smallSecureImageMarkedClient = createTestClient(onlyPid);
+        const auto largeSecureImageMarkedClient = createTestClient(onlyPid);
+        const auto largestSecureImageActiveClient = createTestClient(onlyPid);
+        {
+            std::vector<MediaResourceParcel> resources;
+            resources.push_back(createSecureImageCodecResource(1));
+            mService->addResource(onlyPid, onlyUid, getId(smallSecureImageMarkedClient),
+                    smallSecureImageMarkedClient, resources);
+            resources.clear();
+            resources.push_back(createSecureImageCodecResource(2));
+            mService->addResource(onlyPid, onlyUid, getId(largeSecureImageMarkedClient),
+                    largeSecureImageMarkedClient, resources);
+            resources.clear();
+            resources.push_back(createSecureImageCodecResource(3));
+            mService->addResource(onlyPid, onlyUid, getId(largestSecureImageActiveClient),
+                    largestSecureImageActiveClient, resources);
+        }
+        mService->markClientForPendingRemoval(onlyPid, getId(smallSecureImageMarkedClient));
+        mService->markClientForPendingRemoval(onlyPid, getId(largeSecureImageMarkedClient));
+        // don't mark the largest client
+
+        // non-secure image codec
+        const auto smallNonSecureImageMarkedClient = createTestClient(onlyPid);
+        const auto largeNonSecureImageMarkedClient = createTestClient(onlyPid);
+        const auto largestNonSecureImageActiveClient = createTestClient(onlyPid);
+        {
+            std::vector<MediaResourceParcel> resources;
+            resources.push_back(createNonSecureImageCodecResource(1));
+            mService->addResource(onlyPid, onlyUid, getId(smallNonSecureImageMarkedClient),
+                    smallNonSecureImageMarkedClient, resources);
+            resources.clear();
+            resources.push_back(createNonSecureImageCodecResource(2));
+            mService->addResource(onlyPid, onlyUid, getId(largeNonSecureImageMarkedClient),
+                    largeNonSecureImageMarkedClient, resources);
+            resources.clear();
+            resources.push_back(createNonSecureImageCodecResource(3));
+            mService->addResource(onlyPid, onlyUid, getId(largestNonSecureImageActiveClient),
+                    largestNonSecureImageActiveClient, resources);
+        }
+        mService->markClientForPendingRemoval(onlyPid, getId(smallNonSecureImageMarkedClient));
+        mService->markClientForPendingRemoval(onlyPid, getId(largeNonSecureImageMarkedClient));
+        // don't mark the largest client
+
+        // graphic memory
+        const auto smallGraphicMemoryMarkedClient = createTestClient(onlyPid);
+        const auto largeGraphicMemoryMarkedClient = createTestClient(onlyPid);
+        const auto largestGraphicMemoryActiveClient = createTestClient(onlyPid);
+        {
+            std::vector<MediaResourceParcel> resources;
+            resources.push_back(createGraphicMemoryResource(100));
+            mService->addResource(onlyPid, onlyUid, getId(smallGraphicMemoryMarkedClient),
+                    smallGraphicMemoryMarkedClient, resources);
+            resources.clear();
+            resources.push_back(createGraphicMemoryResource(200));
+            mService->addResource(onlyPid, onlyUid, getId(largeGraphicMemoryMarkedClient),
+                    largeGraphicMemoryMarkedClient, resources);
+            resources.clear();
+            resources.push_back(createGraphicMemoryResource(300));
+            mService->addResource(onlyPid, onlyUid, getId(largestGraphicMemoryActiveClient),
+                    largestGraphicMemoryActiveClient, resources);
+        }
+        mService->markClientForPendingRemoval(onlyPid, getId(smallGraphicMemoryMarkedClient));
+        mService->markClientForPendingRemoval(onlyPid, getId(largeGraphicMemoryMarkedClient));
+        // don't mark the largest client
+
+        // DRM session
+        const auto smallDrmSessionMarkedClient = createTestClient(onlyPid);
+        const auto largeDrmSessionMarkedClient = createTestClient(onlyPid);
+        const auto largestDrmSessionActiveClient = createTestClient(onlyPid);
+        {
+            std::vector<MediaResourceParcel> resources;
+            resources.push_back(createDrmSessionResource(1));
+            mService->addResource(onlyPid, onlyUid, getId(smallDrmSessionMarkedClient),
+                    smallDrmSessionMarkedClient, resources);
+            resources.clear();
+            resources.push_back(createDrmSessionResource(2));
+            mService->addResource(onlyPid, onlyUid, getId(largeDrmSessionMarkedClient),
+                    largeDrmSessionMarkedClient, resources);
+            resources.clear();
+            resources.push_back(createDrmSessionResource(3));
+            mService->addResource(onlyPid, onlyUid, getId(largestDrmSessionActiveClient),
+                    largestDrmSessionActiveClient, resources);
+        }
+        mService->markClientForPendingRemoval(onlyPid, getId(smallDrmSessionMarkedClient));
+        mService->markClientForPendingRemoval(onlyPid, getId(largeDrmSessionMarkedClient));
+        // don't mark the largest client
+
+        // battery
+        const auto batteryMarkedClient = createTestClient(onlyPid);
+        {
+            std::vector<MediaResourceParcel> resources;
+            resources.push_back(createBatteryResource());
+            mService->addResource(onlyPid, onlyUid, getId(batteryMarkedClient),
+                    batteryMarkedClient, resources);
+        }
+        mService->markClientForPendingRemoval(onlyPid, getId(batteryMarkedClient));
+
+        // CPU boost
+        const auto cpuBoostMarkedClient = createTestClient(onlyPid);
+        {
+            std::vector<MediaResourceParcel> resources;
+            resources.push_back(createCpuBoostResource());
+            mService->addResource(onlyPid, onlyUid, getId(cpuBoostMarkedClient),
+                    cpuBoostMarkedClient, resources);
+        }
+        mService->markClientForPendingRemoval(onlyPid, getId(cpuBoostMarkedClient));
+
+        // now we expect that we only reclaim resources from the biggest marked client
+        EXPECT_TRUE(mService->reclaimResourcesFromClientsPendingRemoval(onlyPid).isOk());
+        // secure video codec
+        EXPECT_FALSE(toTestClient(smallSecureVideoMarkedClient)->checkIfReclaimedAndReset());
+        EXPECT_TRUE(toTestClient(largeSecureVideoMarkedClient)->checkIfReclaimedAndReset());
+        EXPECT_FALSE(toTestClient(largestSecureVideoActiveClient)->checkIfReclaimedAndReset());
+        // non-secure video codec
+        EXPECT_FALSE(toTestClient(smallNonSecureVideoMarkedClient)->checkIfReclaimedAndReset());
+        EXPECT_TRUE(toTestClient(largeNonSecureVideoMarkedClient)->checkIfReclaimedAndReset());
+        EXPECT_FALSE(toTestClient(largestNonSecureVideoActiveClient)->checkIfReclaimedAndReset());
+        // secure audio codec
+        EXPECT_FALSE(toTestClient(smallSecureAudioMarkedClient)->checkIfReclaimedAndReset());
+        EXPECT_TRUE(toTestClient(largeSecureAudioMarkedClient)->checkIfReclaimedAndReset());
+        EXPECT_FALSE(toTestClient(largestSecureAudioActiveClient)->checkIfReclaimedAndReset());
+        // non-secure audio codec
+        EXPECT_FALSE(toTestClient(smallNonSecureAudioMarkedClient)->checkIfReclaimedAndReset());
+        EXPECT_TRUE(toTestClient(largeNonSecureAudioMarkedClient)->checkIfReclaimedAndReset());
+        EXPECT_FALSE(toTestClient(largestNonSecureAudioActiveClient)->checkIfReclaimedAndReset());
+        // secure image codec
+        EXPECT_FALSE(toTestClient(smallSecureImageMarkedClient)->checkIfReclaimedAndReset());
+        EXPECT_TRUE(toTestClient(largeSecureImageMarkedClient)->checkIfReclaimedAndReset());
+        EXPECT_FALSE(toTestClient(largestSecureImageActiveClient)->checkIfReclaimedAndReset());
+        // non-secure image codec
+        EXPECT_FALSE(toTestClient(smallNonSecureImageMarkedClient)->checkIfReclaimedAndReset());
+        EXPECT_TRUE(toTestClient(largeNonSecureImageMarkedClient)->checkIfReclaimedAndReset());
+        EXPECT_FALSE(toTestClient(largestNonSecureImageActiveClient)->checkIfReclaimedAndReset());
+        // graphic memory
+        EXPECT_FALSE(toTestClient(smallGraphicMemoryMarkedClient)->checkIfReclaimedAndReset());
+        EXPECT_TRUE(toTestClient(largeGraphicMemoryMarkedClient)->checkIfReclaimedAndReset());
+        EXPECT_FALSE(toTestClient(largestGraphicMemoryActiveClient)->checkIfReclaimedAndReset());
+        // DRM session
+        EXPECT_FALSE(toTestClient(smallDrmSessionMarkedClient)->checkIfReclaimedAndReset());
+        EXPECT_TRUE(toTestClient(largeDrmSessionMarkedClient)->checkIfReclaimedAndReset());
+        EXPECT_FALSE(toTestClient(largestDrmSessionActiveClient)->checkIfReclaimedAndReset());
+        // battery is not expected to be reclaimed when marked as pending removal
+        EXPECT_FALSE(toTestClient(batteryMarkedClient)->checkIfReclaimedAndReset());
+        // CPU boost is not expected to be reclaimed when marked as pending removal
+        EXPECT_FALSE(toTestClient(cpuBoostMarkedClient)->checkIfReclaimedAndReset());
+    }
 };
 
 TEST_F(ResourceManagerServiceTest, config) {
@@ -768,19 +1203,15 @@
     testGetLowestPriorityPid();
 }
 
-TEST_F(ResourceManagerServiceTest, getBiggestClient_l) {
-    testGetBiggestClient();
-}
-
 TEST_F(ResourceManagerServiceTest, isCallingPriorityHigher_l) {
     testIsCallingPriorityHigher();
 }
 
-TEST_F(ResourceManagerServiceTest, testBatteryStats) {
+TEST_F(ResourceManagerServiceTest, batteryStats) {
     testBatteryStats();
 }
 
-TEST_F(ResourceManagerServiceTest, testCpusetBoost) {
+TEST_F(ResourceManagerServiceTest, cpusetBoost) {
     testCpusetBoost();
 }
 
@@ -792,4 +1223,25 @@
     testMarkClientForPendingRemoval();
 }
 
+TEST_F(ResourceManagerServiceTest, reclaimResources_withVideoCodec_reclaimsOnlyVideoCodec) {
+    testReclaimResources_withVideoCodec_reclaimsOnlyVideoCodec();
+}
+
+TEST_F(ResourceManagerServiceTest, reclaimResources_withAudioCodec_reclaimsOnlyAudioCodec) {
+    testReclaimResources_withAudioCodec_reclaimsOnlyAudioCodec();
+}
+
+TEST_F(ResourceManagerServiceTest, reclaimResources_withImageCodec_reclaimsOnlyImageCodec) {
+    testReclaimResources_withImageCodec_reclaimsOnlyImageCodec();
+}
+
+TEST_F(ResourceManagerServiceTest, reclaimResources_whenPartialResourceMatch_reclaims) {
+    testReclaimResources_whenPartialResourceMatch_reclaims();
+}
+
+TEST_F(ResourceManagerServiceTest,
+        reclaimResourcesFromMarkedClients_removesBiggestMarkedClientForSomeResources) {
+    testReclaimResourcesFromMarkedClients_removesBiggestMarkedClientForSomeResources();
+}
+
 } // namespace android
diff --git a/services/mediaresourcemanager/test/ResourceObserverService_test.cpp b/services/mediaresourcemanager/test/ResourceObserverService_test.cpp
index acd9df1..003569d 100644
--- a/services/mediaresourcemanager/test/ResourceObserverService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceObserverService_test.cpp
@@ -116,6 +116,26 @@
 
 const EventTracker::Event EventTracker::NoEvent;
 
+static MediaResource createSecureVideoCodecResource(int amount = 1) {
+    return MediaResource(MediaResource::Type::kSecureCodec,
+        MediaResource::SubType::kVideoCodec, amount);
+}
+
+static MediaResource createNonSecureVideoCodecResource(int amount = 1) {
+    return MediaResource(MediaResource::Type::kNonSecureCodec,
+        MediaResource::SubType::kVideoCodec, amount);
+}
+
+static MediaResource createSecureAudioCodecResource(int amount = 1) {
+    return MediaResource(MediaResource::Type::kSecureCodec,
+        MediaResource::SubType::kAudioCodec, amount);
+}
+
+static MediaResource createNonSecureAudioCodecResource(int amount = 1) {
+    return MediaResource(MediaResource::Type::kNonSecureCodec,
+        MediaResource::SubType::kAudioCodec, amount);
+}
+
 // Operators for GTest macros.
 bool operator==(const EventTracker::Event& lhs, const EventTracker::Event& rhs) {
     return lhs.type == rhs.type && lhs.uid == rhs.uid && lhs.pid == rhs.pid &&
@@ -233,30 +253,30 @@
 
     std::vector<MediaResourceParcel> resources;
     // Add secure video codec.
-    resources = {MediaResource::CodecResource(1 /*secure*/, 1 /*video*/)};
+    resources = {createSecureVideoCodecResource()};
     mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources);
     EXPECT_EQ(mTestObserver1->pop(), EventTracker::Busy(kTestUid1, kTestPid1, observables1));
     EXPECT_EQ(mTestObserver2->pop(), EventTracker::NoEvent);
     EXPECT_EQ(mTestObserver3->pop(), EventTracker::Busy(kTestUid1, kTestPid1, observables1));
 
     // Add non-secure video codec.
-    resources = {MediaResource::CodecResource(0 /*secure*/, 1 /*video*/)};
+    resources = {createNonSecureVideoCodecResource()};
     mService->addResource(kTestPid2, kTestUid2, getId(mTestClient2), mTestClient2, resources);
     EXPECT_EQ(mTestObserver1->pop(), EventTracker::NoEvent);
     EXPECT_EQ(mTestObserver2->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables2));
     EXPECT_EQ(mTestObserver3->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables2));
 
     // Add secure & non-secure video codecs.
-    resources = {MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
-                 MediaResource::CodecResource(0 /*secure*/, 1 /*video*/)};
+    resources = {createSecureVideoCodecResource(),
+                 createNonSecureVideoCodecResource()};
     mService->addResource(kTestPid2, kTestUid2, getId(mTestClient3), mTestClient3, resources);
     EXPECT_EQ(mTestObserver1->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables1));
     EXPECT_EQ(mTestObserver2->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables2));
     EXPECT_EQ(mTestObserver3->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables3));
 
     // Add additional audio codecs, should be ignored.
-    resources.push_back(MediaResource::CodecResource(1 /*secure*/, 0 /*video*/));
-    resources.push_back(MediaResource::CodecResource(0 /*secure*/, 0 /*video*/));
+    resources.push_back(createSecureAudioCodecResource());
+    resources.push_back(createNonSecureAudioCodecResource());
     mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources);
     EXPECT_EQ(mTestObserver1->pop(), EventTracker::Busy(kTestUid1, kTestPid1, observables1));
     EXPECT_EQ(mTestObserver2->pop(), EventTracker::Busy(kTestUid1, kTestPid1, observables2));
@@ -276,9 +296,9 @@
 
     // Add multiple secure & non-secure video codecs.
     // Multiple entries of the same type should be merged, count should be propagated correctly.
-    resources = {MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
-                 MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
-                 MediaResource::CodecResource(0 /*secure*/, 1 /*video*/, 3 /*count*/)};
+    resources = {createSecureVideoCodecResource(),
+                 createSecureVideoCodecResource(),
+                 createNonSecureVideoCodecResource(3)};
     observables1 = {{MediaObservableType::kVideoSecureCodec, 2}};
     observables2 = {{MediaObservableType::kVideoNonSecureCodec, 3}};
     observables3 = {{MediaObservableType::kVideoSecureCodec, 2},
@@ -300,7 +320,7 @@
 
     std::vector<MediaResourceParcel> resources;
     // Add secure video codec to client1.
-    resources = {MediaResource::CodecResource(1 /*secure*/, 1 /*video*/)};
+    resources = {createSecureVideoCodecResource()};
     mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources);
     EXPECT_EQ(mTestObserver1->pop(), EventTracker::Busy(kTestUid1, kTestPid1, observables1));
     EXPECT_EQ(mTestObserver2->pop(), EventTracker::NoEvent);
@@ -322,7 +342,7 @@
     EXPECT_EQ(mTestObserver3->pop(), EventTracker::NoEvent);
 
     // Add non-secure video codec to client2.
-    resources = {MediaResource::CodecResource(0 /*secure*/, 1 /*video*/)};
+    resources = {createNonSecureVideoCodecResource()};
     mService->addResource(kTestPid2, kTestUid2, getId(mTestClient2), mTestClient2, resources);
     EXPECT_EQ(mTestObserver1->pop(), EventTracker::NoEvent);
     EXPECT_EQ(mTestObserver2->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables2));
@@ -344,24 +364,24 @@
     EXPECT_EQ(mTestObserver3->pop(), EventTracker::NoEvent);
 
     // Add secure & non-secure video codecs, plus audio codecs (that's ignored).
-    resources = {MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
-                 MediaResource::CodecResource(0 /*secure*/, 1 /*video*/),
-                 MediaResource::CodecResource(1 /*secure*/, 0 /*video*/),
-                 MediaResource::CodecResource(0 /*secure*/, 0 /*video*/)};
+    resources = {createSecureVideoCodecResource(),
+                 createNonSecureVideoCodecResource(),
+                 createSecureAudioCodecResource(),
+                 createNonSecureAudioCodecResource()};
     mService->addResource(kTestPid2, kTestUid2, getId(mTestClient3), mTestClient3, resources);
     EXPECT_EQ(mTestObserver1->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables1));
     EXPECT_EQ(mTestObserver2->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables2));
     EXPECT_EQ(mTestObserver3->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables3));
     // Remove one audio codec, should have no event.
-    resources = {MediaResource::CodecResource(1 /*secure*/, 0 /*video*/)};
+    resources = {createSecureAudioCodecResource()};
     mService->removeResource(kTestPid2, getId(mTestClient3), resources);
     EXPECT_EQ(mTestObserver1->pop(), EventTracker::NoEvent);
     EXPECT_EQ(mTestObserver2->pop(), EventTracker::NoEvent);
     EXPECT_EQ(mTestObserver3->pop(), EventTracker::NoEvent);
     // Remove the other audio codec and the secure video codec, only secure video codec
     // removal should be reported.
-    resources = {MediaResource::CodecResource(0 /*secure*/, 0 /*video*/),
-                 MediaResource::CodecResource(1 /*secure*/, 1 /*video*/)};
+    resources = {createNonSecureAudioCodecResource(),
+                 createSecureVideoCodecResource()};
     mService->removeResource(kTestPid2, getId(mTestClient3), resources);
     EXPECT_EQ(mTestObserver1->pop(), EventTracker::Idle(kTestUid2, kTestPid2, observables1));
     EXPECT_EQ(mTestObserver2->pop(), EventTracker::NoEvent);
@@ -386,10 +406,10 @@
 
     // Add multiple secure & non-secure video codecs, plus audio codecs (that's ignored).
     // (ResourceManager will merge these internally.)
-    resources = {MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
-                 MediaResource::CodecResource(0 /*secure*/, 1 /*video*/, 4 /*count*/),
-                 MediaResource::CodecResource(1 /*secure*/, 0 /*video*/),
-                 MediaResource::CodecResource(0 /*secure*/, 0 /*video*/)};
+    resources = {createSecureVideoCodecResource(),
+                 createNonSecureVideoCodecResource(4),
+                 createSecureAudioCodecResource(),
+                 createNonSecureAudioCodecResource()};
     mService->addResource(kTestPid2, kTestUid2, getId(mTestClient3), mTestClient3, resources);
     observables1 = {{MediaObservableType::kVideoSecureCodec, 1}};
     observables2 = {{MediaObservableType::kVideoNonSecureCodec, 4}};
@@ -400,10 +420,10 @@
     EXPECT_EQ(mTestObserver3->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables3));
     // Remove one audio codec, 2 secure video codecs and 2 non-secure video codecs.
     // 1 secure video codec removal and 2 non-secure video codec removals should be reported.
-    resources = {MediaResource::CodecResource(0 /*secure*/, 0 /*video*/),
-                 MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
-                 MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
-                 MediaResource::CodecResource(0 /*secure*/, 1 /*video*/, 2 /*count*/)};
+    resources = {createNonSecureAudioCodecResource(),
+                 createSecureVideoCodecResource(),
+                 createSecureVideoCodecResource(),
+                 createNonSecureVideoCodecResource(2)};
     mService->removeResource(kTestPid2, getId(mTestClient3), resources);
     observables1 = {{MediaObservableType::kVideoSecureCodec, 1}};
     observables2 = {{MediaObservableType::kVideoNonSecureCodec, 2}};
@@ -443,8 +463,8 @@
     std::vector<MediaResourceParcel> resources;
 
     // Add secure & non-secure video codecs.
-    resources = {MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
-                 MediaResource::CodecResource(0 /*secure*/, 1 /*video*/)};
+    resources = {createSecureVideoCodecResource(),
+                 createNonSecureVideoCodecResource()};
     mService->addResource(kTestPid2, kTestUid2, getId(mTestClient3), mTestClient3, resources);
     EXPECT_EQ(mTestObserver1->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables1));
     EXPECT_EQ(mTestObserver2->pop(), EventTracker::NoEvent);