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

NullPointerExceptions In cardinalmobilesdk #326

Closed ersen-lw closed 1 year ago

ersen-lw commented 2 years ago

General information

Issue description

I've been getting some crash reports from Crashlytics about this issue.

The crash occurred in the cardinalcommerce library. ChallengeUtils.java line 2 com.cardinalcommerce.shared.cs.userinterfaces.ChallengeUtils.a

The Crashlytics report claims the device was in Landscape so I reckon the user went through a configuration change. Looking at the issue with the NullPointer with Context, I am going to assume the cardinalcommerce is holding onto a Context reference and calling getApplicationContext() on a reference that is no longer present during config change.

Fatal Exception: java.lang.RuntimeException: An error occurred while executing doInBackground()
       at android.os.AsyncTask$4.done(AsyncTask.java:415)
       at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
       at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
       at java.util.concurrent.FutureTask.run(FutureTask.java:271)
       at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:305)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
       at java.lang.Thread.run(Thread.java:923)

Caused by java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Context android.content.Context.getApplicationContext()' on a null object reference
       at com.cardinalcommerce.shared.cs.userinterfaces.ChallengeUtils.a(ChallengeUtils.java:2)
       at com.cardinalcommerce.shared.cs.userinterfaces.ChallengeUtils.a(ChallengeUtils.java:41)
       at com.cardinalcommerce.shared.cs.f.m.a(m.java:46)
       at com.cardinalcommerce.cardinalmobilesdk.a.c.d.a(d.java:84)
       at com.cardinalcommerce.shared.cs.d.a.a(a.java:191)
       at com.cardinalcommerce.shared.cs.d.a.doInBackground(a.java:2)
       at android.os.AsyncTask$3.call(AsyncTask.java:394)
       at java.util.concurrent.FutureTask.run(FutureTask.java:266)
       at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:305)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
       at java.lang.Thread.run(Thread.java:923)

I also got another crash report, one second later from the same device. I decided to combine them rather than raise a separate issue because I think they are related. I guess this may have been the Activity behind the one above which tries to perform the challenge which also crashed.

Fatal Exception: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.wam.android/com.braintreepayments.api.ThreeDSecureActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String r6.f.e()' on a null object reference
       at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3472)
       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3636)
       at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
       at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
       at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2084)
       at android.os.Handler.dispatchMessage(Handler.java:106)
       at android.os.Looper.loop(Looper.java:223)
       at android.app.ActivityThread.main(ActivityThread.java:7887)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:981)

Caused by java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String r6.f.e()' on a null object reference
       at com.cardinalcommerce.cardinalmobilesdk.a.a.a.a(a.java:318)
       at com.cardinalcommerce.cardinalmobilesdk.Cardinal.cca_continue(Cardinal.java:2)
       at com.braintreepayments.api.CardinalClient.continueLookup(CardinalClient.java:44)
       at com.braintreepayments.api.ThreeDSecureActivity.onCreateInternal(ThreeDSecureActivity.java:39)
       at com.braintreepayments.api.ThreeDSecureActivity.onCreate(ThreeDSecureActivity.java:28)
       at android.app.Activity.performCreate(Activity.java:8019)
       at android.app.Activity.performCreate(Activity.java:8003)
       at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1310)
       at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3445)
       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3636)
       at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
       at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
       at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2084)
       at android.os.Handler.dispatchMessage(Handler.java:106)
       at android.os.Looper.loop(Looper.java:223)
       at android.app.ActivityThread.main(ActivityThread.java:7887)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:981)

I'd be happy to provide more implementation details but not sure what would be useful since the stacktrace refers to obfuscated properties and methods. Let me know what would be of help here. Thank you

sarahkoop commented 2 years ago

Hi @ersen-lw - Thanks for using the Braintree Drop-in SDK. We will report this issue to Cardinal. I see you discovered this from crash logs, but are you able to provide consistent steps to reproduce? Steps to reproduce would likely help their investigation of this issue.

ersen-lw commented 2 years ago

Hello, apologies for the late reply. I have not been able to reproduce these crashes but I receive crash reports about it from time to time. Would it be possible for the Cardinal development team to receive these stacktraces to unobfuscate them and provide some more details. It may help determine how to reproduce it.

Here is another crash report I received. Android 11 OPPO A72.

Fatal Exception: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.wam.android/com.braintreepayments.api.ThreeDSecureActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String r6.f.e()' on a null object reference
       at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3720)
       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3887)
       at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
       at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:140)
       at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:100)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2317)
       at android.os.Handler.dispatchMessage(Handler.java:106)
       at android.os.Looper.loop(Looper.java:263)
       at android.app.ActivityThread.main(ActivityThread.java:8283)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:612)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1006)

Caused by java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String r6.f.e()' on a null object reference
       at com.cardinalcommerce.cardinalmobilesdk.a.a.a.a(a.java:318)
       at com.cardinalcommerce.cardinalmobilesdk.Cardinal.cca_continue(Cardinal.java:2)
       at com.braintreepayments.api.CardinalClient.continueLookup(CardinalClient.java:44)
       at com.braintreepayments.api.ThreeDSecureActivity.onCreateInternal(ThreeDSecureActivity.java:39)
       at com.braintreepayments.api.ThreeDSecureActivity.onCreate(ThreeDSecureActivity.java:28)
       at android.app.Activity.performCreate(Activity.java:8146)
       at android.app.Activity.performCreate(Activity.java:8130)
       at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1310)
       at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3689)
       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3887)
       at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
       at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:140)
       at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:100)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2317)
       at android.os.Handler.dispatchMessage(Handler.java:106)
       at android.os.Looper.loop(Looper.java:263)
       at android.app.ActivityThread.main(ActivityThread.java:8283)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:612)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1006)
m-s-morgan commented 1 year ago

@sarahkoop I'm receiving this same error while attempting to upgrade to version 6.6.0 and the latest braintree_android SDK: java.lang.RuntimeException: Unable to start activity ComponentInfo{**.*****.****/com.braintreepayments.api.ThreeDSecureActivity}: java.lang.NullPointerException: Attempt to read from field 'java.lang.String com.cardinalcommerce.a.configure.getInstance' on a null object reference in method 'void com.cardinalcommerce.cardinalmobilesdk.Cardinal.cca_continue(java.lang.String, java.lang.String, android.app.Activity, com.cardinalcommerce.cardinalmobilesdk.services.CardinalValidateReceiver)' It occurs when a 3DS (v2) request is attempting to perform a challenge. The app immediately crashes. Is there something that needs to be implemented to allow for 3DS challenges? We are passing in a Fragment and not an Activity to the DropinClient. Not sure if that could be a cause or not.

m-s-morgan commented 1 year ago

@sarahkoop this is a critical issue for our team at the moment and I just want to make sure this thread is still being monitored. Thank you in advance.

sshropshire commented 1 year ago

Hi @m-s-morgan I wonder if this is related to the following GitHub issue we just submitted a fix for: https://github.com/braintree/braintree_android/issues/641. The issue filed has an unobfuscated stack trace that seems similar in nature. Once this is merged in we can update our DropIn library to see if this resolves the issue.

m-s-morgan commented 1 year ago

@sshropshire really appreciate the response! Do you have any idea on a timeline for the merge and update just so that our team can plan accordingly?

Also, do the 3DS verifications work fine in your test apps currently? Do you have any test apps using a Fragment and not an Activity for the DropInClient? It just seems strange to me that this isn't a bigger issue for more people so I want to make sure it's not something we're just doing wrong on our end. Thank you again!

soarb commented 1 year ago

@sshropshire I don't know if this helps at all, but in our React Native app (on the Android side of things) we've switched to using Android's SplashScreen API.

This required a few changes to our build.gradle, Android.manifest and more specifically our styles.xml. Initially our application's theme must now use a style which extends Theme.SplashScreen.

Now, as @m-s-morgan mentioned, as soon as we use a test card which launches a 3DS challenge our App crashes in the background with the very same error Attempt to read from field 'java.lang.String com.cardinalcommerce.a.configure.getInstance' on a null object...

Additionally in LogCat's stack trace we're also now seeing java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.

Prior to this switch all 3DS verifications both in Sandbox and Production have been working without any issues.

I'll try and provide more information if required but here's a snippet from the stacktrace

m-s-morgan commented 1 year ago

@sshropshire letting you know that we updated to 6.7.0 and the problem still exists. We are getting a similar stacktrace to @soarb above.

@soarb are you also using a Fragment with your DropInClient?

soarb commented 1 year ago

@m-s-morgan, @sshropshire apologies but my knowledge about the Android eco system is a little sketchy hence the use of React Native :) (which has served me well until hitting issues requiring me to dig a little deeper of course!)

The version of React Native we're currently using 0.70.4 launches our application as a FragmentActivity which ultimately inherits from the Activity base class via some convoluted androidx hierarchy, so I'm going to say "No" in this instance, that we're not using a Fragment.

All instances of the DropInClient or indeed any of the other clients e.g., BraintreeClient, ThreeDSecureClient, GooglePayClient are provided this FragmentActivity instance during our main Activity's onCreate() method.

The Drop In UI (other than a few other little issues I've raised on Github) works fine. As does the BraintreeClient and GooglePayClient (e.g., showing the Google Payment sheet).

However, anything that triggers the 3DS Browser Switch to perform authentication causes this crash in our test Sandbox (with appropriate test card number).

I must stress again though that it seems to be the switch to the new Android 12 SplashScreen API that's causing this.

It requires that our application's theme extend from Theme.Splashscreen which does NOT appear to inherit from Theme.AppCompat.

If I simply switch our Application's theme back to the original (which does inherit from Theme.AppCompat) we don't get any crashes - of course we then get issues with the SplashScreen API as we've not met the requirement of our application theme using Theme.SplashScreen :(

It also appears we may have arrived at the same issue with the Cardinal Mobile SDK (or maybe Braintree's usage of it?) via two different paths?

Very happy for people to correct me on this issue and as always can provide more information!

Cheers

Ben

soarb commented 1 year ago

@sshropshire any update on this please? i'd like to understand why my app crashes when the Braintree SDK launches the 3DS challenge. All I've done is incorporate the necessary changes required to support the Android 12 SplashScreen API which means my Application's theme must initially extend Theme.SplashScreen. If I simply change my application's theme back to the original (which extends Theme.AppCompat) everything is fine.

I think I have a work around but it's not in line with Google's guidelines, just be interested to know what's causing the crash?

Cheers

Benj

sshropshire commented 1 year ago

@ersen-lw still looking into this at the moment. I agree, deobfuscation may help but at the least we can get them a stack trace to see if it helps resolve the issue more quickly.

@m-s-morgan We haven't seen any issues in our Demo app at the moment with 3DS v2 verifications. Our demo application also uses a fragment when instantiating a ThreeDSecureClient. The only case I can think of that would be problematic with Fragment is if it isn't attached to an Activity when a 3DS verification is initiated.

@soarb We'll have to investigate further for Theme.SplashScreen. I wouldn't be surprised if this causes an issue though since it's a new major version of Android.

@m-s-morgan do you have a stack trace available I could send to Cardinal as well?

m-s-morgan commented 1 year ago

@sshropshire

23-01-20 14:48:51.844 24188-24188/io.xxx.xxx E/AndroidRuntime: FATAL EXCEPTION: main
    Process: io.xxx.xxx, PID: 24188
    java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
        at androidx.appcompat.app.AppCompatDelegateImpl.createSubDecor(AppCompatDelegateImpl.java:852)
        at androidx.appcompat.app.AppCompatDelegateImpl.ensureSubDecor(AppCompatDelegateImpl.java:815)
        at androidx.appcompat.app.AppCompatDelegateImpl.onPostCreate(AppCompatDelegateImpl.java:536)
        at androidx.appcompat.app.AppCompatActivity.onPostCreate(AppCompatActivity.java:151)
        at android.app.Instrumentation.callActivityOnPostCreate(Instrumentation.java:1458)
        at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3728)
        at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:221)
        at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201)
        at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2308)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loopOnce(Looper.java:201)
        at android.os.Looper.loop(Looper.java:288)
        at android.app.ActivityThread.main(ActivityThread.java:7898)
        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)
2023-01-20 14:48:53.420 24188-24469/io.xxx.xxx E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!  (parcel size = 1024)
2023-01-20 14:48:54.150 24687-24687/io.xxx.xxx E/AndroidRuntime: FATAL EXCEPTION: main
    Process: io.xxx.xxx, PID: 24687
    java.lang.RuntimeException: Unable to start activity ComponentInfo{io.xxx.xxx/com.braintreepayments.api.ThreeDSecureActivity}: java.lang.NullPointerException: Attempt to read from field 'java.lang.String com.cardinalcommerce.a.configure.getInstance' on a null object reference in method 'void com.cardinalcommerce.cardinalmobilesdk.Cardinal.cca_continue(java.lang.String, java.lang.String, android.app.Activity, com.cardinalcommerce.cardinalmobilesdk.services.CardinalValidateReceiver)'
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3676)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3813)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:101)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2308)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loopOnce(Looper.java:201)
        at android.os.Looper.loop(Looper.java:288)
        at android.app.ActivityThread.main(ActivityThread.java:7898)
        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.lang.NullPointerException: Attempt to read from field 'java.lang.String com.cardinalcommerce.a.configure.getInstance' on a null object reference in method 'void com.cardinalcommerce.cardinalmobilesdk.Cardinal.cca_continue(java.lang.String, java.lang.String, android.app.Activity, com.cardinalcommerce.cardinalmobilesdk.services.CardinalValidateReceiver)'
        at com.cardinalcommerce.cardinalmobilesdk.Cardinal.cca_continue(:22082)
        at com.braintreepayments.api.CardinalClient.continueLookup(CardinalClient.java:44)
        at com.braintreepayments.api.ThreeDSecureActivity.onCreateInternal(ThreeDSecureActivity.java:43)
        at com.braintreepayments.api.ThreeDSecureActivity.onCreate(ThreeDSecureActivity.java:31)
        at android.app.Activity.performCreate(Activity.java:8290)
        at android.app.Activity.performCreate(Activity.java:8269)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1384)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3657)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3813) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:101) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2308) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loopOnce(Looper.java:201) 
        at android.os.Looper.loop(Looper.java:288) 
        at android.app.ActivityThread.main(ActivityThread.java:7898) 
        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

@ersen-lw @m-s-morgan @soarb maybe ThreeDSecureActivity in the Braintree SDK needs to use Theme.AppCompat. I made this PR and once it's approved we'll update the core dependency in this repo to update DropIn. We can see if this helps resolve the issue.

sshropshire commented 1 year ago

@ersen-lw @m-s-morgan @soarb ThreeDSecureActivity now uses Theme.AppCompat in the latest 6.8.0 version. Please reply here if the issues persists (or is resolved 🤞).

m-s-morgan commented 1 year ago

@sshropshire it works! Really appreciate the effort that went into getting this resolved. Take care.

sshropshire commented 1 year ago

@m-s-morgan awesome! Thanks for the feedback! I'll close this for now. We'll keep an eye open for regressions but it sounds like we should be good.

soarb commented 1 year ago

@sshropshire really appreciate your work on this! I've been on annual leave so only just seen the new release, I'll get onto it as soon as I can and confirm, but I suspect things will be good!

soarb commented 1 year ago

all good here too thanks @sshropshire :)