-
Notifications
You must be signed in to change notification settings - Fork 253
Closed
Description
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
- Launch the app with Leak Canary enabled.
- Use the Braintree SDK to present the PayPal Native Checkout bottom sheet.
- Close the bottom sheet using the "X" button without selecting any options (credit card or ship to).
- Repeat steps 2 and 3 multiple times.
- 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
Metadata
Metadata
Assignees
Labels
No labels
