eclipsesource / tabris-js

Create native mobile apps in JavaScript or TypeScript.
https://tabrisjs.com
BSD 3-Clause "New" or "Revised" License
1.4k stars 170 forks source link

Android wakeup from "deep sleep" #902

Closed dested closed 8 years ago

dested commented 8 years ago

After my application is backgrounded for a few hours, if I try to open the application I get the following warnings to the console, followed by the app not rendering at all. We have a number of plugins installed to the application but none of them ever caused us issues in a regular cordova environment. The fact that the application does not draw at all is a huge issue. In the event these errors fire, the app should at least restart itself, even if there is a bit of flicker to the user.

Could not create object "cordova.plugin" (reason: Could not find IOperationDelegate for null)
Could not listen to event "finish" (reason: The parameter 'type' in call ParamCheck.notNull() must not be null)
Could not call method "exec" (reason: The parameter 'type' in call ParamCheck.notNull() must not be null)
Could not create object "cordova.plugin" (reason: Could not find IOperationDelegate for null)
Could not listen to event "finish" (reason: The parameter 'type' in call ParamCheck.notNull() must not be null)
Could not call method "exec" (reason: The parameter 'type' in call ParamCheck.notNull() must not be null)
deviceready has not fired after 5 seconds.
Channel not fired: onCordovaInfoReady

We have no code in the tabris.app.on("resume").

Here is the list of plugins we are using for reference.

com.batch.cordova 1.5.3 "Batch"
com.oauthio.plugins.oauthio 0.2.4 "OAuth.io"
cordova-custom-config 2.0.0 "cordova-custom-config"
cordova-plugin-bluetoothle 4.0.0 "Bluetooth LE"
cordova-plugin-compat 1.0.0 "Compat"
cordova-plugin-datepicker 0.9.3 "DatePicker"
cordova-plugin-device 1.1.2 "Device"
cordova-plugin-dialogs 1.2.1 "Notification"
cordova-plugin-geolocation 2.2.1-dev "Geolocation"
cordova-plugin-globalization 1.0.3 "Globalization"
cordova-plugin-health 0.5.4 "Cordova Health"
cordova-plugin-inappbrowser 1.4.0 "InAppBrowser"
cordova-plugin-intercom 1.1.7 "Intercom"
cordova-plugin-listpicker 2.2.2 "ListPicker"
cordova-plugin-spinner-dialog 1.3.1 "SpinnerDialog"
cordova-plugin-whitelist 1.2.2 "Whitelist"
cordova-plugin-x-socialsharing 5.1.1 "SocialSharing"
cordova-plugin-x-toast 2.5.2 "Toast"

bugreport-2016-06-16-16-50-36

mpost commented 8 years ago

I think the app was been killed while in the background and would now be restarted by the system. The creation of the "cordova.plugin" in the first line of the log happens very early in the app startup. It is the "wiring infrastructure" to communicate with cordova plugins. Why this could not be instantiates is not entirely clear to me.

Did you find a way to reproduce the problem?

dested commented 8 years ago

After much trial and error I have been able to reproduce it consistently. I have attached the project.

  1. Turn your android to developer mode
  2. Go to developer options in settings
  3. Change background process limit to "No background processes". This expidites the error.
  4. Add tabris android to the project
  5. Deploy the app the phone as normal
  6. App runs without issue
  7. Minimize the app
  8. Open another app
  9. Open another app
  10. Open the running app list (the square button in the bottom right of your phone)
  11. Choose the test app
  12. It should crash with the above errors

It seems to be related to the plugins "cordova-plugin-device" and "cordova-plugin-intercom", but I have not debugged any further to figure out why.

If you have any issues reproducing please let me know. test2.zip

dested commented 8 years ago

Its hard for me to debug, but I was able to track it down to this line in the device plugin

channel.waitForInitialization('onCordovaInfoReady');

When I remove this line, it still throws the warnings, but the application continues. I'm sure the implications of removing this line within the plugin is damning, but it allowed me to narrow down specifically what causes the app to crash. Hope this helps

mpost commented 8 years ago

Thanks for the info. We will investigate the issue.

dested commented 8 years ago

I was wondering if there was any update on this. It is truly a devastating issue and gap in cordova plugin functionality. Do you foresee a resolution in 1.9?

mpost commented 8 years ago

Not yet but we will look into it for the 1.9 release.

mpost commented 8 years ago

@dested We have looked into the issue with the steps above but couldn't reproduce the crash.

We added the plugin cordova-plugin-device and used the devices dev settings Don't keep activities activated. Opening the app, pressing home (app gets killed) and opening it again from the recents menu (which restarts the app) resulted in a normal start of the app.

Might the problem occur when multiple of the plugins you mentioned above are combined?

dested commented 8 years ago

Correct, it is not the device plugin alone, it has to have the intercom plugin as well. Were you not able to reproduce it with project I attached and going through the steps? I was able to consistently reproduce it following the steps above with test2.zip project.

mpost commented 8 years ago

@dested Okay i see your point. With the added intercom plugin (1.1.7) i am seeing the following native java error:

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'io.intercom.android.sdk.api.Api io.intercom.android.sdk.Bridge.api()' on a null object reference
  at io.intercom.android.sdk.Bridge.getApi(Bridge.java:80)
  at io.intercom.android.sdk.IntercomBridge$1.run(IntercomBridge.java:36)
  at android.app.Activity.runOnUiThread(Activity.java:5849)
  at io.intercom.android.sdk.IntercomBridge.pluginInitialize(IntercomBridge.java:33)                                                   

I have given the following preferences:

<preference name="intercom-app-id" value="your_app_id"/>
<preference name="intercom-android-api-key" value="android_sdk-..."/>

These are obviously invalid but that should not crash the sdk i would think.

Is there anything else to take care of?

dested commented 8 years ago

I don't believe so. I was never able to get low enough to see the actual Android exception being thrown, only the warnings in the console. Is the null pointer on the tabris side, and is it fixable? Does this cause the sample project I uploaded to resume after a deep sleep?

mpost commented 8 years ago

@dested We have tried your example and are seeing the following output:

test2-example

The image was taken on an Android Emulator running Android 7.0 with the latest nightly tabris android cordova platform.

dested commented 8 years ago

I am running the test2 project on android 6.0 with https://tabrisjs.com/api/v1/downloads/latest/android and getting the errors still. I want to reiterate that it does not happen the first time around, only after the app has been backgrounded so far that android free's its memory. When it comes back I get the following errors image I do not currently have a 7.0 emulator to test with, but it if is working for you, then the issue may be 6.0 specific.

mpost commented 8 years ago

The good (or bad news): We were able to reproduce the problem on Android 7 with the latest nightly tabris-android using your test2 example.

mpost commented 8 years ago

I have debugged the scenario... A little tricky to attach the debugger when the app process is just about to get restarted... Therefore we have added some more log statements in the 1.9 release to give more information in the Android logcat when exceptions are thrown.

None the less i have narrowed down the problem to the following exception:

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'io.intercom.android.sdk.api.Api io.intercom.android.sdk.Bridge.api()' on a null object reference
    at io.intercom.android.sdk.Bridge.getApi(Bridge.java:80)
    at io.intercom.android.sdk.IntercomBridge$1.run(IntercomBridge.java:36)
    at android.app.Activity.runOnUiThread(Activity.java:5849)
    at io.intercom.android.sdk.IntercomBridge.pluginInitialize(IntercomBridge.java:33)
    at org.apache.cordova.CordovaPlugin.privateInitialize(CordovaPlugin.java:58)
    at org.apache.cordova.PluginManager.getPlugin(PluginManager.java:172)
    at org.apache.cordova.PluginManager.startupPlugins(PluginManager.java:98)
    at org.apache.cordova.PluginManager.init(PluginManager.java:87)
    at org.apache.cordova.CordovaWebViewImpl.init(CordovaWebViewImpl.java:116)
    at com.eclipsesource.tabris.android.cordova.TabrisWebView.init(TabrisWebView.java:54)
    at com.eclipsesource.tabris.android.cordova.CordovaPluginOperator.createWebView(CordovaPluginOperator.java:53)
    at com.eclipsesource.tabris.android.cordova.CordovaPluginOperator.<init>(CordovaPluginOperator.java:44)
    ... 24 more

The intercom plugin forwards a call to the intercom sdk which is in an inconsistent state. The intercom plugin call is here: https://github.com/intercom/intercom-cordova/blob/master/src/android/IntercomBridge.java#L36

dested commented 8 years ago

Very very interesting. Can you think of a reason why this would work in a regular cordova application but not a tabris app? Do you feel the bug is in the intercom implementation such that I should post an issue over there?

As a stop gap, do you know of any way I can modify the intercom bridge code to wait a tick to call that method? If so I can simply customize the plugin locally to get past this issue.

I really appreciate your support on this.

mpost commented 8 years ago

With the latest nightly build you will see the exception in the android logcat. You could play around with the plugin to try to narrow down the problem or report to them. They could be interested since there sdk can be brought into a state that causes a crash.

dested commented 8 years ago

I have opened a ticket on their side. Thank you for all the help tracking this down. Moral of the story seems to be that if an exception gets thrown by a plugin in the pluginInitialize phase it crashes tabris, you may want to consider wrapping this in a try catch and bubbling the error up to the javascript console, which would allow the plugin to fail in potentially unexpected ways, but at least the application can continue to run. It's kind of a crapshoot either way really, but it seems more graceful. Im going to go ahead a close this at this point unless they come back with anything that would be meaningful to tabris.

Thanks!

mpost commented 8 years ago

@dested We previously caught exceptions from the pluginInitialize phase and the app continued to work beyond that point as expect. But as mentioned above we now made changes so that you can actually find the exception in the Android log (not in the dev console as we don't want to expose client specific traces there). Be aware that you app as to be build in debug mode for any output to be logged to logcat.