braintree / braintree-android-drop-in

Braintree Drop-In SDK for Android
https://developers.braintreepayments.com/guides/drop-in/android/v2
MIT License
124 stars 79 forks source link

Adding Venmo payment method crashes #392

Closed jbreitfeller-sfix closed 1 year ago

jbreitfeller-sfix commented 1 year ago

General information

Issue description

Whenever I click to add a Venmo payment method, I receive this error. I was able to fix this by clearing the data on my app but I wasn't sure if maybe there was some idea as to why this was happening in the first place.

FATAL EXCEPTION: main
                 Process: com.stitchfix.stitchfix.beta.debug, PID: 22369
                 android.os.BadParcelableException: Parcelable encountered IOException writing serializable object (name = com.braintreepayments.api.BraintreeSharedPreferencesException)
                    at android.os.Parcel.writeSerializable(Parcel.java:2751)
                    at android.os.Parcel.writeValue(Parcel.java:2517)
                    at android.os.Parcel.writeValue(Parcel.java:2316)
                    at android.os.Parcel.writeArrayMapInternal(Parcel.java:1265)
                    at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1802)
                    at android.os.Bundle.writeToParcel(Bundle.java:1389)
                    at android.os.Parcel.writeBundle(Parcel.java:1334)
                    at android.content.Intent.writeToParcel(Intent.java:11573)
                    at android.os.Parcel.writeTypedObject(Parcel.java:2157)
                    at android.app.IActivityClientController$Stub$Proxy.finishActivity(IActivityClientController.java:1427)
                    at android.app.ActivityClient.finishActivity(ActivityClient.java:165)
                    at android.app.Activity.finish(Activity.java:6688)
                    at android.app.Activity.finish(Activity.java:6705)
                    at com.braintreepayments.api.DropInActivity.finishDropInWithError(DropInActivity.java:118)
                    at com.braintreepayments.api.DropInActivity.onError(DropInActivity.java:386)
                    at com.braintreepayments.api.DropInActivity.lambda$startVenmoFlow$10$com-braintreepayments-api-DropInActivity(DropInActivity.java:420)
                    at com.braintreepayments.api.DropInActivity$$ExternalSyntheticLambda16.onResult(Unknown Source:2)
                    at com.braintreepayments.api.VenmoClient$2$1$1.onAuthorizationResult(VenmoClient.java:195)
                    at com.braintreepayments.api.AuthorizationLoader.loadAuthorization(AuthorizationLoader.java:20)
                    at com.braintreepayments.api.BraintreeClient.getAuthorization(BraintreeClient.java:210)
                    at com.braintreepayments.api.VenmoClient$2$1.onResult(VenmoClient.java:187)
                    at com.braintreepayments.api.VenmoApi$1.onResult(VenmoApi.java:49)
                    at com.braintreepayments.api.HttpClient$2.run(HttpClient.java:123)
                    at android.os.Handler.handleCallback(Handler.java:942)
                    at android.os.Handler.dispatchMessage(Handler.java:99)
                    at android.os.Looper.loopOnce(Looper.java:201)
                    at android.os.Looper.loop(Looper.java:288)
                    at android.app.ActivityThread.main(ActivityThread.java:7872)
                    at java.lang.reflect.Method.invoke(Native Method)
                    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
                    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
                 Caused by: java.io.NotSerializableException: com.google.crypto.tink.proto.Keyset
                    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1240)
                    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1604)
                    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1565)
                    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1488)
                    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1234)
                    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1604)
                    at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:463)
                    at java.lang.Throwable.writeObject(Throwable.java:1058)
                    at java.lang.reflect.Method.invoke(Native Method)
                    at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:1036)
                    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1552)
                    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1488)
                    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1234)
                    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:354)
                    at android.os.Parcel.writeSerializable(Parcel.java:2746)
                    at android.os.Parcel.writeValue(Parcel.java:2517) 
                    at android.os.Parcel.writeValue(Parcel.java:2316) 
                    at android.os.Parcel.writeArrayMapInternal(Parcel.java:1265) 
                    at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1802) 
                    at android.os.Bundle.writeToParcel(Bundle.java:1389) 
                    at android.os.Parcel.writeBundle(Parcel.java:1334) 
                    at android.content.Intent.writeToParcel(Intent.java:11573) 
                    at android.os.Parcel.writeTypedObject(Parcel.java:2157) 
                    at android.app.IActivityClientController$Stub$Proxy.finishActivity(IActivityClientController.java:1427) 
                    at android.app.ActivityClient.finishActivity(ActivityClient.java:165) 
                    at android.app.Activity.finish(Activity.java:6688) 
                    at android.app.Activity.finish(Activity.java:6705) 
                    at com.braintreepayments.api.DropInActivity.finishDropInWithError(DropInActivity.java:118) 
                    at com.braintreepayments.api.DropInActivity.onError(DropInActivity.java:386) 
                    at com.braintreepayments.api.DropInActivity.lambda$startVenmoFlow$10$com-braintreepayments-api-DropInActivity(DropInActivity.java:420) 
                    at com.braintreepayments.api.DropInActivity$$ExternalSyntheticLambda16.onResult(Unknown Source:2) 
                    at com.braintreepayments.api.VenmoClient$2$1$1.onAuthorizationResult(VenmoClient.java:195) 
                    at com.braintreepayments.api.AuthorizationLoader.loadAuthorization(AuthorizationLoader.java:20) 
                    at com.braintreepayments.api.BraintreeClient.getAuthorization(BraintreeClient.java:210) 
                    at com.braintreepayments.api.VenmoClient$2$1.onResult(VenmoClient.java:187) 
                    at com.braintreepayments.api.VenmoApi$1.onResult(VenmoApi.java:49) 
                    at com.braintreepayments.api.HttpClient$2.run(HttpClient.java:123) 
                    at android.os.Handler.handleCallback(Handler.java:942) 
                    at android.os.Handler.dispatchMessage(Handler.java:99) 
                    at android.os.Looper.loopOnce(Looper.java:201) 
                    at android.os.Looper.loop(Looper.java:288) 
                    at android.app.ActivityThread.main(ActivityThread.java:7872) 
                    at java.lang.reflect.Method.invoke(Native Method) 
                    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548) 
                    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936) 
sshropshire commented 1 year ago

Hi @jbreitfeller-sfix thanks for using the Braintree SDK for Android. I'm not sure exactly what would cause this error, but it appears to be coming from the 3rd party Jetpack library we're using for encrypted shared prefs.

Is this 100% reproducible? If so, could you set a break point here in DropInActivity.java and inspect the error?

jbreitfeller-sfix commented 1 year ago

I'll see if I can find a device to recreate this on again. After clearing my data on the phone, the issue went away. I'll say we had a similar issue with EncryptedSharedPreferences, but that was when a user would backup our app and then migrate to a different phone. Essentially, the encryption key on the device would no longer match the file and would throw an odd error like this. We ended up just catching that exception, deleting the shared preferences, and then re-opening the file.

That may have been the case here as well... 🤔

jbreitfeller-sfix commented 1 year ago

If I modify the BraintreeApi.xml shared preferences file I am able to recreate the same stack trace that I received above. The actual error ends up saying

com.braintreepayments.api.BraintreeSharedPreferencesException: Unable to obtain a reference to encrypted shared preferences.

As I mentioned above, we've seen this happen within our own apps encrypted preferences when a user migrated from an old phone to a new phone. This is because the shared preference file is copied over but the encryption key is obviously no longer the same. We solved this two ways

  1. Excluding the shared preference files in our fullBackupContent and dataExtractionRules application tag.
  2. Adding code to catch an exception for being unable to parse the encrypted shared preferences and then just wiping the file. We did this because it appeared that certain devices were ignoring the above mentioned rules.
sshropshire commented 1 year ago

@jbreitfeller-sfix we've removed EncryptedSharedPreferences in the latest 6.8.0 version. Hopefully the quality of this library will improve in the future. Feel free to re-open if this issue persists within our SDK!