Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Memory Leak - MainPaysheetViewModel #1140

Open
jclemus91 opened this issue Sep 5, 2024 · 0 comments
Open

Memory Leak - MainPaysheetViewModel #1140

jclemus91 opened this issue Sep 5, 2024 · 0 comments

Comments

@jclemus91
Copy link

jclemus91 commented Sep 5, 2024

Braintree SDK Version

4.45.0

Environment

Sandbox

Android Version & Device

Android 14 - Pixel 5

Braintree dependencies

braintree_version = '4.45.0'
"com.braintreepayments.api:paypal-native-checkout:$braintree_version"
"com.braintreepayments.api:data-collector:$braintree_version"

leak_canary_version = '2.14'
"com.squareup.leakcanary:leakcanary-android:$leak_canary_version"

Describe the bug

I've found a memory leak in the sandbox environment (I haven't been able to test production build due to company policies), when using PayPal Native Checkout for Android, Leak Canary identifies the leak related to the com.paypal.pyplcheckout.ui.feature.home.viewmodel.MainPaysheetViewModel, after repeatedly opening and closing the PayPal sheet, it appears that the authListener and doAfterAuth are not being properly released, leading to memory retention.

┬───
│ GC Root: Thread object
│
├─ WV.Yc instance
│    Leaking: NO (PathClassLoader↓ is not leaking)
│    Thread name: 'CleanupReference'
│    ↓ Thread.contextClassLoader
├─ dalvik.system.PathClassLoader instance
│    Leaking: NO (LocalBroadcastManager↓ is not leaking and A ClassLoader is
│    never leaking)
│    ↓ ClassLoader.runtimeInternalObjects
├─ java.lang.Object[] array
│    Leaking: NO (LocalBroadcastManager↓ is not leaking)
│    ↓ Object[3987]
├─ androidx.localbroadcastmanager.content.LocalBroadcastManager class
│    Leaking: NO (a class is never leaking)
│    ↓ static LocalBroadcastManager.mInstance
│                                   ~~~~~~~~~
├─ androidx.localbroadcastmanager.content.LocalBroadcastManager instance
│    Leaking: UNKNOWN
│    Retaining 1.8 kB in 63 objects
│    mAppContext instance of com.**package**..
│    ↓ LocalBroadcastManager.mReceivers
│                            ~~~~~~~~~~
├─ java.util.HashMap instance
│    Leaking: UNKNOWN
│    Retaining 296 B in 14 objects
│    ↓ HashMap[key()]
│             ~~~~~~~
├─ com.paypal.authcore.authentication.Authenticator$a instance
│    Leaking: UNKNOWN
│    Retaining 20 B in 1 objects
│    ↓ Authenticator$a.a
│                      ~
├─ com.paypal.authcore.authentication.Authenticator instance
│    Leaking: UNKNOWN
│    Retaining 13.5 kB in 357 objects
│    j instance of **package**
│    ↓ Authenticator.g
│                    ~
├─ com.paypal.pyplcheckout.flavorauth.
│  WebBasedAuthAccessTokenUseCase$invoke$authDelegate$1 instance
│    Leaking: UNKNOWN
│    Retaining 7.9 kB in 291 objects
│    Anonymous class implementing com.paypal.authcore.authentication.
│    AuthenticationDelegate
│    ↓ WebBasedAuthAccessTokenUseCase$invoke$authDelegate$1.$authListener
│                                                           ~~~~~~~~~~~~~
├─ com.paypal.pyplcheckout.data.repositories.auth.AuthHandler instance
│    Leaking: UNKNOWN
│    Retaining 7.9 kB in 290 objects
│    ↓ AuthHandler.doAfterAuth
│                  ~~~~~~~~~~~
├─ com.paypal.pyplcheckout.ui.feature.home.viewmodel.
│  MainPaysheetViewModel$$ExternalSyntheticLambda19 instance
│    Leaking: UNKNOWN
│    Retaining 7.7 kB in 280 objects
│    ↓ MainPaysheetViewModel$$ExternalSyntheticLambda19.f$0
│                                                       ~~~
╰→ com.paypal.pyplcheckout.ui.feature.home.viewmodel.MainPaysheetViewModel
​  instance
​     Leaking: YES (ObjectWatcher was watching this because com.paypal.
​     pyplcheckout.ui.feature.home.viewmodel.MainPaysheetViewModel received
​     ViewModel#onCleared() callback)
​     Retaining 7.7 kB in 279 objects
​     key = f663730b-63f4-4e57-9cfe-30493c07613e
​     watchDurationMillis = 14555
​     retainedDurationMillis = 9542
METADATA
Build.VERSION.SDK_INT: 34
Build.MANUFACTURER: Google
LeakCanary version: 2.14

The issue is also replicable in the sample app Demo.
demo_sample_app.m4v.zip

┬───
│ GC Root: Thread object
│
├─ android.net.ConnectivityThread instance
│    Leaking: NO (PathClassLoader↓ is not leaking)
│    Thread name: 'ConnectivityThread'
│    ↓ Thread.contextClassLoader
├─ dalvik.system.PathClassLoader instance
│    Leaking: NO (LocalBroadcastManager↓ is not leaking and A ClassLoader is
│    never leaking)
│    ↓ ClassLoader.runtimeInternalObjects
├─ java.lang.Object[] array
│    Leaking: NO (LocalBroadcastManager↓ is not leaking)
│    ↓ Object[5152]
├─ androidx.localbroadcastmanager.content.LocalBroadcastManager class
│    Leaking: NO (a class is never leaking)
│    ↓ static LocalBroadcastManager.mInstance
│                                   ~~~~~~~~~
├─ androidx.localbroadcastmanager.content.LocalBroadcastManager instance
│    Leaking: UNKNOWN
│    Retaining 1.1 kB in 42 objects
│    mAppContext instance of com.braintreepayments.demo.DemoApplication
│    ↓ LocalBroadcastManager.mReceivers
│                            ~~~~~~~~~~
├─ java.util.HashMap instance
│    Leaking: UNKNOWN
│    Retaining 248 B in 11 objects
│    ↓ HashMap[key()]
│             ~~~~~~~
├─ com.paypal.authcore.authentication.Authenticator$a instance
│    Leaking: UNKNOWN
│    Retaining 20 B in 1 objects
│    ↓ Authenticator$a.a
│                      ~
├─ com.paypal.authcore.authentication.Authenticator instance
│    Leaking: UNKNOWN
│    Retaining 13.1 kB in 350 objects
│    j instance of com.braintreepayments.demo.DemoApplication
│    ↓ Authenticator.g
│                    ~
├─ com.paypal.pyplcheckout.flavorauth.
│  WebBasedAuthAccessTokenUseCase$invoke$authDelegate$1 instance
│    Leaking: UNKNOWN
│    Retaining 7.8 kB in 287 objects
│    Anonymous class implementing com.paypal.authcore.authentication.
│    AuthenticationDelegate
│    ↓ WebBasedAuthAccessTokenUseCase$invoke$authDelegate$1.$authListener
│                                                           ~~~~~~~~~~~~~
├─ com.paypal.pyplcheckout.data.repositories.auth.AuthHandler instance
│    Leaking: UNKNOWN
│    Retaining 7.8 kB in 286 objects
│    ↓ AuthHandler.doAfterAuth
│                  ~~~~~~~~~~~
├─ com.paypal.pyplcheckout.ui.feature.home.viewmodel.
│  MainPaysheetViewModel$$ExternalSyntheticLambda2 instance
│    Leaking: UNKNOWN
│    Retaining 7.6 kB in 276 objects
│    ↓ MainPaysheetViewModel$$ExternalSyntheticLambda2.f$0
│                                                      ~~~
╰→ com.paypal.pyplcheckout.ui.feature.home.viewmodel.MainPaysheetViewModel
​  instance
​     Leaking: YES (ObjectWatcher was watching this because com.paypal.
​     pyplcheckout.ui.feature.home.viewmodel.MainPaysheetViewModel received
​     ViewModel#onCleared() callback)
​     Retaining 7.5 kB in 275 objects
​     key = b06b4aab-5c7c-4281-ab13-9cb1be930733
​     watchDurationMillis = 26553
​     retainedDurationMillis = 21553

METADATA

Build.VERSION.SDK_INT: 34
Build.MANUFACTURER: Google
LeakCanary version: 2.14
App process name: com.braintreepayments.demo
Class count: 32964
Instance count: 773845
Primitive array count: 398000
Object array count: 35951
Thread count: 170
Heap total bytes: 75853523
Bitmap count: 1
Bitmap total bytes: 834901
Large bitmap count: 0
Large bitmap total bytes: 0
Db 1: open /data/user/0/com.braintreepayments.demo/databases/analytics_database
Db 2: open /data/user/0/com.braintreepayments.demo/no_backup/androidx.work.
workdb
Stats: LruCache[maxSize=3000,hits=168996,misses=358719,hitRate=32%]
RandomAccess[bytes=26805425,reads=358719,travel=178941312503,range=92814436,size
=105548749]
Analysis duration: 44462 ms

To reproduce

  1. Launch the app with Leak Canary enabled.
  2. Use the Braintree SDK to present the PayPal Native Checkout bottom sheet.
  3. Close the bottom sheet using the "X" button without selecting any options (credit card or ship to).
  4. Repeat steps 2 and 3 multiple times.
  5. Wait for Leak Canary to analyze and observe the reported memory leak.

Expected behavior

After closing the PayPal Native Checkout sheet, all resources should be released properly.

Screenshots

Screenshot 2024-09-04 at 6 15 34 p m

@jclemus91 jclemus91 changed the title Memory Leak Memory Leak - MainPaysheetViewModel Sep 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant