adobe / adobe/aepsdk-core-android

DataMarshaller repeatedly calls toString() on extras causing memory pressure

Closed Beginner friendly
#791 2 comments 0 reactions 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.