Fix CASE Churn caused by subscriptions on tv (#23616)

* Fix CASE Churn caused by subscriptions on tv

* Address comments

* User feature flag for IM fix since it only applies when both server and controller are enabled

* Address feedback

* fix build
diff --git a/examples/tv-app/tv-common/include/CHIPProjectAppConfig.h b/examples/tv-app/tv-common/include/CHIPProjectAppConfig.h
index c9ddf74..395be25 100644
--- a/examples/tv-app/tv-common/include/CHIPProjectAppConfig.h
+++ b/examples/tv-app/tv-common/include/CHIPProjectAppConfig.h
@@ -33,6 +33,9 @@
 // TVs need to be both commissioners and commissionees
 #define CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE 1
 
+// See issue 23625.
+#define CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE 1
+
 // TVs that are not commissionees,
 // or that don't automatically enter commissioning mode should set this to 0
 #define CHIP_DEVICE_CONFIG_ENABLE_PAIRING_AUTOSTART 1
diff --git a/examples/tv-casting-app/tv-casting-common/include/MediaSubscriptionBase.h b/examples/tv-casting-app/tv-casting-common/include/MediaSubscriptionBase.h
index e2a065e..73e4eb4 100644
--- a/examples/tv-casting-app/tv-casting-common/include/MediaSubscriptionBase.h
+++ b/examples/tv-casting-app/tv-casting-common/include/MediaSubscriptionBase.h
@@ -39,6 +39,7 @@
                                  mTvEndpoint);
 
         return cluster.template SubscribeAttribute<TypeInfo>(context, successFn, failureFn, minInterval, maxInterval,
-                                                             onSubscriptionEstablished);
+                                                             onSubscriptionEstablished, nullptr /* resubscribeCb */,
+                                                             true /* fabricFiltered */, true /* keepPreviousSubscriptions */);
     }
 };
diff --git a/src/app/ReadHandler.cpp b/src/app/ReadHandler.cpp
index 5b9a292..bc7cfac 100644
--- a/src/app/ReadHandler.cpp
+++ b/src/app/ReadHandler.cpp
@@ -46,6 +46,11 @@
     VerifyOrDie(apExchangeContext != nullptr);
 
     mExchangeCtx.Grab(apExchangeContext);
+#if CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
+    // TODO: this should be replaced by a pointer to the InteractionModelEngine that created the ReadHandler
+    // once InteractionModelEngine is no longer a singleton (see issue 23625)
+    mExchangeMgr = apExchangeContext->GetExchangeMgr();
+#endif // CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
 
     mInteractionType            = aInteractionType;
     mLastWrittenEventsBytes     = 0;
@@ -185,7 +190,11 @@
     {
         VerifyOrReturnLogError(!mExchangeCtx, CHIP_ERROR_INCORRECT_STATE);
         VerifyOrReturnLogError(mSessionHandle, CHIP_ERROR_INCORRECT_STATE);
+#if CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
+        auto exchange = mExchangeMgr->NewContext(mSessionHandle.Get().Value(), this);
+#else  // CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
         auto exchange = InteractionModelEngine::GetInstance()->GetExchangeManager()->NewContext(mSessionHandle.Get().Value(), this);
+#endif // CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
         VerifyOrReturnLogError(exchange != nullptr, CHIP_ERROR_INCORRECT_STATE);
         mExchangeCtx.Grab(exchange);
     }
@@ -205,7 +214,11 @@
     {
         VerifyOrReturnLogError(!mExchangeCtx, CHIP_ERROR_INCORRECT_STATE);
         VerifyOrReturnLogError(mSessionHandle, CHIP_ERROR_INCORRECT_STATE);
+#if CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
+        auto exchange = mExchangeMgr->NewContext(mSessionHandle.Get().Value(), this);
+#else  // CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
         auto exchange = InteractionModelEngine::GetInstance()->GetExchangeManager()->NewContext(mSessionHandle.Get().Value(), this);
+#endif // CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
         VerifyOrReturnLogError(exchange != nullptr, CHIP_ERROR_INCORRECT_STATE);
         mExchangeCtx.Grab(exchange);
     }
diff --git a/src/app/ReadHandler.h b/src/app/ReadHandler.h
index cf0ee7a..c4f1472 100644
--- a/src/app/ReadHandler.h
+++ b/src/app/ReadHandler.h
@@ -436,6 +436,11 @@
     SessionHolder mSessionHandle;
 
     Messaging::ExchangeHolder mExchangeCtx;
+#if CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
+    // TODO: this should be replaced by a pointer to the InteractionModelEngine that created the ReadHandler
+    // once InteractionModelEngine is no longer a singleton (see issue 23625)
+    Messaging::ExchangeManager * mExchangeMgr = nullptr;
+#endif // CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
 
     ObjectList<AttributePathParams> * mpAttributePathList   = nullptr;
     ObjectList<EventPathParams> * mpEventPathList           = nullptr;
diff --git a/src/include/platform/CHIPDeviceConfig.h b/src/include/platform/CHIPDeviceConfig.h
index cd9d78b..5dfc6fc 100644
--- a/src/include/platform/CHIPDeviceConfig.h
+++ b/src/include/platform/CHIPDeviceConfig.h
@@ -1125,6 +1125,18 @@
 #endif
 
 /**
+ * CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
+ *
+ * See issue 23625.
+ *
+ * Needs to be 1 when the following is 1:
+ *  CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
+ */
+#ifndef CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
+#define CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE 0
+#endif
+
+/**
  * CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT
  *
  * Enable or disable whether this device will attempt to