openid / AppAuth-Android

Android client SDK for communicating with OAuth 2.0 and OpenID Connect providers.
https://openid.github.io/AppAuth-Android
Apache License 2.0
2.79k stars 876 forks source link

NPE on AuthorizationManagementActivity.onResume (from Android framework?) #318

Open zoltanf opened 6 years ago

zoltanf commented 6 years ago

I can't reproduce it myself, but on an app with around half million active users it's happening on production from time to time. (we are using the latest AppAuth version 0.7.0).

Usually happening on these devices:

NPE:

java.lang.NullPointerException: android.app.Instrumentation in Attempt to invoke virtual method 'boolean android.content.Intent.migrateExtraStreamToClipData()' on a null object reference.execStartActivity

Stack trace:

at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4225)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4327)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3426)
at android.app.ActivityThread.access$1100(ActivityThread.java:229)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1821)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:7331)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.content.Intent.migrateExtraStreamToClipData()' on a null object reference
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1534)
at android.app.Activity.startActivityForResult(Activity.java:4298)
at android.app.Activity.startActivityForResult(Activity.java:4245)
at android.app.Activity.startActivity(Activity.java:4582)
at android.app.Activity.startActivity(Activity.java:4550)
at net.openid.appauth.AuthorizationManagementActivity.onResume(AuthorizationManagementActivity.java)
at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1287)
at android.app.Activity.performResume(Activity.java:7015)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4214)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4327)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3426)
at android.app.ActivityThread.access$1100(ActivityThread.java:229)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1821)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:7331)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
iainmcgin commented 6 years ago

Hmm, can't see from the code exactly what we could be doing wrong that would trigger this. From some googling around, Do you know whether the devices in question are rooted, or are devices that don't have Google Play Services installed? Searching for related errors brought that as related in some cases.

What percentage of your user base does this affect?

zoltanf commented 6 years ago

Thanks for checking. It's a really low percentage of users affected (would say well bellow 1%) but it is still happening. I can't say if the users are on rooted devices, it's possible, however they do have Google Play Services since our app also requires it.

zoltanf commented 6 years ago

Our tester has managed to reproduce this problem. This happens if the user interrupts the flow, by following steps:

Stacktrace from our reproduction:

Android: 8.1.0
Android Build: OPP6.171019.012
Manufacturer: LGE
Model: Nexus 5X
Thread: main-2
CrashReporter Key: 178ec6e2-b9b0-428d-908f-bbc7e8bc8f7b
Start Date: 2018-03-09T15:12:31.570Z
Date: 2018-03-09T15:21:13.380Z

java.lang.RuntimeException: Unable to resume activity {com.marktguru.android.beta/net.openid.appauth.AuthorizationManagementActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.content.Intent.migrateExtraStreamToClipData()' on a null object reference
    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3581)
    at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3621)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2862)
    at android.app.ActivityThread.-wrap11(Unknown Source:0)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:164)
    at android.app.ActivityThread.main(ActivityThread.java:6494)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.content.Intent.migrateExtraStreamToClipData()' on a null object reference
    at android.app.Instrumentation.execStartActivity(Instrumentation.java:1609)
    at android.app.Activity.startActivityForResult(Activity.java:4487)
    at android.app.Activity.startActivityForResult(Activity.java:4445)
    at android.app.Activity.startActivity(Activity.java:4806)
    at android.app.Activity.startActivity(Activity.java:4774)
    at net.openid.appauth.AuthorizationManagementActivity.onResume(AuthorizationManagementActivity.java:218)
    at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1355)
    at android.app.Activity.performResume(Activity.java:7107)
    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3556)
    ... 10 more
tamaskarai commented 6 years ago

Hi,

Any update on this issue? We also got a a few hundred crashes from this one with the same stacktrace.

phusung commented 6 years ago

I fixed it by restore there value. Then everything is ok @Override protected void onResume() { super.onResume();

    if (savedInstanceState != null) {
        mAuthIntent = savedInstanceState.getParcelable(KEY_AUTH_INTENT);
        try {
            String authRequestJson = savedInstanceState.getString(KEY_AUTH_REQUEST, null);
            mAuthRequest = authRequestJson != null
                    ? AuthorizationRequest.jsonDeserialize(authRequestJson)
                    : null;
        } catch (JSONException ex) {
            throw new IllegalStateException("Unable to deserialize authorization request", ex);
        }
        mCompleteIntent = savedInstanceState.getParcelable(KEY_COMPLETE_INTENT);
        mCancelIntent = savedInstanceState.getParcelable(KEY_CANCEL_INTENT);
    }
    if (!mAuthorizationStarted) {
        startActivity(mAuthIntent);
        mAuthorizationStarted = true;
        return;
    }
    if (getIntent().getData() != null) {
        handleAuthorizationComplete();
    } else {
        handleAuthorizationCanceled();
    }
    finish();
}
zoltanf commented 6 years ago

@phusung can you please do a pull request for this?

zoltanf commented 6 years ago

@phusung I looked into it and I'm not sure that is the right way to solve this problem. There is a clear way to reproduce this problem given above. Since the problematic call happens after the auth flow is completed (interrupted), it should somehow be just completely ignored. At the moment I'm unsure how to implement this check properly on the state restoration of the AuthorizationManagementActivity.

I would still suggest you make a pull request to the project and then the code can be reviewed by someone who is a contributor.

phusung commented 6 years ago

@zoltanf I have not permission to commit my code. Other way, It's fixed by adding: @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); if(savedInstanceState != null) { extractState(savedInstanceState); } }

zoltanf commented 6 years ago

@phusung don't try to commit directly to the repo, but instead create a pull request. You can do this by forking the project and then look for instructions here.

richardn100 commented 6 years ago

Hi, any update on this crash? About 500 users are experiencing it every day for me, and several had emailed me about it.

I can recreate the crash from @zoltanf's comment above, but I doubt real users are doing that exact flow. Any workaround or idea on the fix to this crash please?

Thanks.

richardn100 commented 5 years ago

Hi, I believe I found the cause for this crash:

It occurs when you open the authorization request twice in a row (e.g. double-clicking your app's login button which calls the AppAuth SDK twice via "performAuthorizationRequest" or "getAuthorizationRequestIntent"). The crash occurs after completing the login process and it tries to return back to your app.

I am temporarily fixing this issue by adding a boolean in my app to determine if the authorization is occurring already.

s00mr0 commented 5 years ago

Hi,

I have found the same exception randomly in my project while nation wide roll out.

I found one common reason was that almost all devices have the custom ROM installed. they were not with official OS build.

as per zoltanf, all the list devices in his 1st message are having custom ROM.

Regards

AesSedai101 commented 5 years ago

@phusung will you still be opening a PR for your fix?

dajaffe commented 5 years ago

I was able to reproduce this as well using the steps provided by @phusung. I have a few reported crashes for this isolated to a couple users. I'm consuming AppAuth indirectly via react-native-app-auth. What is the progress on resolving this?

Fideas commented 4 years ago

I just noticed that the exact code that produces a crash in Android 7 and 8.1 works OK in Android 9.

To the people asking about progress about this issue, @phusung sent a PR but never signed the CLA so it was abandoned . I just asked on that PR to see if the solution is indeed appropriate, and if that is the case I, or anyone, can just send the same code in a new PR so we can get this merged

jovanhuxiaowen commented 4 months ago

We also have some users facing this crash with latest version 0.11.1. cannot reproduce with any steps listed above.

Fatal Exception: java.lang.RuntimeException: Unable to resume activity {com.***/net.openid.appauth.AuthorizationManagementActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.content.Intent.migrateExtraStreamToClipData()' on a null object reference at android.app.ActivityThread.performResumeActivity(ActivityThread.java:5083) at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:5126) at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:52) at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:190) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:105) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2618) at android.os.Handler.dispatchMessage(Handler.java:110) at android.os.Looper.loop(Looper.java:219) at android.app.ActivityThread.main(ActivityThread.java:8673) at java.lang.reflect.Method.invoke(Method.java) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1109)

Caused by java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.content.Intent.migrateExtraStreamToClipData()' on a null object reference at android.app.Instrumentation.execStartActivity(Instrumentation.java:1731) at android.app.Activity.startActivityForResult(Activity.java:5412) at com.microsoft.intune.mam.client.app.MAMActivity.startActivityForResultReal(MAMActivity.java:344) at java.lang.reflect.Method.invoke(Method.java) at com.microsoft.intune.mam.InterProxy$InterInvocationHandler.invoke(:84) at java.lang.reflect.Proxy.invoke(Proxy.java:1006) at $Proxy22.startActivityForResultReal() at com.microsoft.intune.mam.client.app.ActivityBehaviorImpl.startActivityForResult(:759) at java.lang.reflect.Method.invoke(Method.java) at com.microsoft.intune.mam.InterProxy$InterInvocationHandler.invoke(:84) at java.lang.reflect.Proxy.invoke(Proxy.java:1006) at $Proxy21.startActivityForResult() at com.microsoft.intune.mam.client.app.MAMActivity.startActivityForResult(MAMActivity.java:301) at androidx.activity.ComponentActivity.startActivityForResult(ComponentActivity.java:709) at android.app.Activity.startActivity(Activity.java:5819) at android.app.Activity.startActivity(Activity.java:5787) at net.openid.appauth.AuthorizationManagementActivity.onMAMResume(AuthorizationManagementActivity.java:228) at java.lang.reflect.Method.invoke(Method.java) at com.microsoft.intune.mam.InterProxy$InterInvocationHandler.invoke(:84) at java.lang.reflect.Proxy.invoke(Proxy.java:1006) at $Proxy22.onMAMResume() at com.microsoft.intune.mam.client.app.ActivityBehaviorImpl.onResume(:427) at java.lang.reflect.Method.invoke(Method.java) at com.microsoft.intune.mam.InterProxy$InterInvocationHandler.invoke(:84) at java.lang.reflect.Proxy.invoke(Proxy.java:1006) at $Proxy21.onResume() at com.microsoft.intune.mam.client.app.MAMActivity.onResume(MAMActivity.java:106) at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1472) at android.app.Activity.performResume(Activity.java:8351) at android.app.ActivityThread.performResumeActivity(ActivityThread.java:5073) at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:5126) at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:52) at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:190) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:105) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2618) at android.os.Handler.dispatchMessage(Handler.java:110) at android.os.Looper.loop(Looper.java:219) at android.app.ActivityThread.main(ActivityThread.java:8673) at java.lang.reflect.Method.invoke(Method.java) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1109)