adobe / adobe/aepsdk-core-android
DataMarshaller repeatedly calls toString() on extras causing memory pressure
- Dominant language
- Kotlin
- Stars
- 17
- Forks
- 30
- Avg merge
- 8h 37m
- Merged PRs (30d)
- 5
Description
`DataMarshaller` repeatedly calls `toString()` on objects that are not used. If an `Activity.intent` holds `Parcelable` Extras it is automatically captured by `MobileCore.collectLaunchInfo`. We have noticed the following lines in OutOfMemory stack traces within crash reports where it is unable to allocate memory for large strings. Is it possible to avoid calling `toString()` on `Parcelable` extras in an `Intent`, especially since the return value is only used to check if the object is empty?
> OBFUSCATED.toString (OBFUSCATED:140)
> java.lang.String.valueOf (String.java:3657)
> java.lang.StringBuilder.append (StringBuilder.java:132)
> java.util.AbstractCollection.toString (AbstractCollection.java:473)
> java.lang.String.valueOf (String.java:3657)
> java.lang.StringBuilder.append (StringBuilder.java:132)
> OBFUSCATED.toString (OBFUSCATED:128)
> com.adobe.marketing.mobile.internal.DataMarshaller.marshalIntentExtras$core_phoneRelease (DataMarshaller.kt:93)
> com.adobe.marketing.mobile.internal.DataMarshaller.marshal (DataMarshaller.kt:63)
> com.adobe.marketing.mobile.MobileCore.collectLaunchInfo (MobileCore.java)
> com.adobe.marketing.mobile.LaunchInfoCollector.onActivityResumed (MobileCoreInitializer.kt:243)
> com.adobe.marketing.mobile.services.internal.context.App$ActivityTracker.onActivityResumed (App.kt:173)
> com.adobe.marketing.mobile.services.internal.context.App$InternalActivityLifecycleCallbacks.onActivityResumed (App.kt:186)
> android.app.Application.dispatchActivityResumed (Application.java:431)
> android.app.Activity.dispatchActivityResumed (Activity.java:1445)
internal fun marshalIntentExtras(intent: Intent, marshalledData: MutableMap) {
val extraBundle = intent.extras ?: return
// First, handle known keys directly to avoid potential exceptions from keySet()
KNOWN_KEYS_MAP.forEach { (originalKey, transformedKey) ->
processAndRemoveKnownKey(extraBundle, originalKey, transformedKey, marshalledData)
}
// Then extract other keys
try {
extraBundle.keySet()?.forEach { key ->
try {
if (KNOWN_KEYS_MAP.containsKey(key)) {
// returning from a lambda expression, the loop will continue.
return@forEach
}
val value = extraBundle[key]
if (value?.toString()?.isNotEmpty() == true) { // toString() can create large String objects that are unused in the rest of this method
marshalledData[key] = value
}
} catch (e: Exception) {
Log.error(CoreConstants.LOG_TAG, LOG_TAG, "Failed to retrieve data (key = $key) from Activity, error is: ${e.message}")
}
}
} catch (e: Exception) {
Log.error(CoreConstants.LOG_TAG, LOG_TAG, "Failed to retrieve data from Activity, error is: ${e.message}")
}
}
Contributor guide
Research direction
Start in DataMarshaller.kt at marshalIntentExtras, especially the code around line 93, and trace its call from MobileCore.collectLaunchInfo. Confirm how non-known Intent extras are handled and ensure completion no longer creates unused large strings through toString() while retaining the intended empty-value check behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, kotlin
- Domain
- mobile-dev
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100