From b118df482f4a9cb19bea50099e86b1eded79dddf Mon Sep 17 00:00:00 2001 From: Mahmoud Elshamy Date: Mon, 11 May 2026 19:16:19 +0400 Subject: [PATCH 1/2] Fix NPE race condition in updateDisplayCountAndDuration --- .../java/com/iterable/iterableapi/EmbeddedSessionManager.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iterableapi/src/main/java/com/iterable/iterableapi/EmbeddedSessionManager.kt b/iterableapi/src/main/java/com/iterable/iterableapi/EmbeddedSessionManager.kt index cbedfe4fd..467fe3bbe 100644 --- a/iterableapi/src/main/java/com/iterable/iterableapi/EmbeddedSessionManager.kt +++ b/iterableapi/src/main/java/com/iterable/iterableapi/EmbeddedSessionManager.kt @@ -108,10 +108,11 @@ public class EmbeddedSessionManager { } private fun updateDisplayCountAndDuration(impressionData: EmbeddedImpressionData): EmbeddedImpressionData { - if (impressionData.start != null) { + val start = impressionData.start + if (start != null) { impressionData.displayCount = impressionData.displayCount.plus(1) impressionData.duration = - impressionData.duration.plus((Date().time - impressionData.start!!.time) / 1000.0) + impressionData.duration.plus((Date().time - start.time) / 1000.0) .toFloat() impressionData.start = null } From 10c734f213fb5657f17998055e2a41824f553dea Mon Sep 17 00:00:00 2001 From: Mahmoud Elshamy Date: Mon, 11 May 2026 19:24:33 +0400 Subject: [PATCH 2/2] Add @Volatile on start field and synchronized block for full thread safety --- .../iterableapi/EmbeddedImpressionData.kt | 2 +- .../iterableapi/EmbeddedSessionManager.kt | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/iterableapi/src/main/java/com/iterable/iterableapi/EmbeddedImpressionData.kt b/iterableapi/src/main/java/com/iterable/iterableapi/EmbeddedImpressionData.kt index e166fa2e9..a8947c052 100644 --- a/iterableapi/src/main/java/com/iterable/iterableapi/EmbeddedImpressionData.kt +++ b/iterableapi/src/main/java/com/iterable/iterableapi/EmbeddedImpressionData.kt @@ -9,7 +9,7 @@ data class EmbeddedImpressionData( val placementId: Long, var displayCount: Int = 0, var duration: Float = 0.0f, - var start: Date? = null + @Volatile var start: Date? = null ) { constructor( messageId: String, diff --git a/iterableapi/src/main/java/com/iterable/iterableapi/EmbeddedSessionManager.kt b/iterableapi/src/main/java/com/iterable/iterableapi/EmbeddedSessionManager.kt index 467fe3bbe..b1271111c 100644 --- a/iterableapi/src/main/java/com/iterable/iterableapi/EmbeddedSessionManager.kt +++ b/iterableapi/src/main/java/com/iterable/iterableapi/EmbeddedSessionManager.kt @@ -108,13 +108,15 @@ public class EmbeddedSessionManager { } private fun updateDisplayCountAndDuration(impressionData: EmbeddedImpressionData): EmbeddedImpressionData { - val start = impressionData.start - if (start != null) { - impressionData.displayCount = impressionData.displayCount.plus(1) - impressionData.duration = - impressionData.duration.plus((Date().time - start.time) / 1000.0) - .toFloat() - impressionData.start = null + synchronized(impressionData) { + val start = impressionData.start + if (start != null) { + impressionData.displayCount = impressionData.displayCount.plus(1) + impressionData.duration = + impressionData.duration.plus((Date().time - start.time) / 1000.0) + .toFloat() + impressionData.start = null + } } return impressionData }