The Android WebView widget appears to enter an unrecoverable state if executed JavaScript code is caught in an infinite loop.
For example, this webpage will cause the problem:
<html>
<head>
<title>FAIL</title>
<script type="text/javascript">
function test() {
while (true);
}
</script>
</head>
<body onload="test();">
Failure Test
</body>
As will simply entering the following URL in any Android browser using WebView:
javascript:while(true);
Once such an infinite loop is encountered, one CPU core will be run at its maximum. The WebView appears to never shut down. This will of course rapidly drain the battery and slow the device. Only terminating the containing application appears to resolve this.
The following appear to be ineffective:
Disabling JavaScript: webView.getSettings().setJavaScriptEnabled(false);
Stopping the page from loading: webView.stopLoading();
Pausing all JS Timers: webView.pauseTimers();
Loading an alternate URL: webView.loadUrl("about:blank");
Removing the WebView from the widget hierarchy: parent.removeView(browserView);
Invoking destroy on the WebView: webView.destroy();
Finishing the activity: activity.finish();
Returning false from WebChromeClient.onJsTimeout(); (This method was deprecated in API 17, and appears to never be invoked).
The following is effective:
Killing the VM: System.exit(0); (This is a method that should never be called on Android.)
It's worth noting that the stock Android browser (not Chrome) suffers this problem as well. Though Chrome does not have the issue, it does still appear to occur when using the Chromium-based WebView shipped in Android 4.4.
Once one WebView enters this state, the application will be unable to load any URL into any other WebViews.
If anyone has any suggestions for terminating a WebView, it'd be greatly appreciated. I can't control the content being loaded into the WebView, as it's being used for a general-purpose browser. Otherwise my default solution will be to attempt to detect the scenario and warn the user if it is encountered, providing the option to forcibly terminate the application to prevent battery drain.
Thank you for any ideas!
I don't think you can do too much about that. Because the WebView is single process (this is true for the 4.4 WebView too) and the renderers are running in your app's process a misbehaving web page can lead to your process being OOM killed by allocating tons of memory.
Chrome doesn't suffer from this problem since it runs the renderer in a separate process which can be killed. The WebView could be modified to kill the thread that JavaScript execution is taking place in, however that would lead to memory leaks (since the OS will not clean up for you like it does in the case of a separate process) and like I said above - doing so doesn't really protect you against a malicious web page allocating memory.
I think your solution of displaying a "the page is not responding. kill the app?" popup to the user is the best you can do using the WebView. The alternative is to create your own multi-process browser based on the Chromium code but that will probably take a lot more effort.
Related
In Android Studio 1.4 using the Nexus5 emulator, every time there is a 3D animation (x, y, rotationX, rotationY, rotationZ) using GSAP in the webview, the logcat spits out a ton of this message:
Attempt to remove non-JNI local reference, dumping thread
This doesn't appear to affect my webapp's behavior other than a bit of stuttering when the message is produced, which is multiple times a second for animations that take a few seconds to complete.
Any ideas on how to stop, or is this even a problem?
UPDATE: The error does not occur on my test device, Samsung Galaxy S4. So it is likely only an emulator problem.
I think you are using a webview without a host GPU emulation.
Google team says in the issue:
"You shouldn't expect that WebView will be usable without host GPU emulation any time soon.
Note also that since the emulator doesn't receive WebView updates, testing on the emulator means you are using a much older version of WebView than the vast majority of your users, and so it's already rather unrepresentative. :/"
Check the issue report:
*https://code.google.com/p/android/issues/detail?id=189040
I'm using the standard PhoneGap plugin for writing to local files via HTML5. In the background my app is downloading data from a server and then saving it to disk as it comes in. Typical file sizes are around 20Mb.
If the user is scrolling the screen or some other UI action when writing is going on, my app will freeze for a second or two on an iPad 2 running iOS7. The file writing operation is wrapped in a setTimeout call (so it doesn't block the main thread) but this doesn't seem to help.
The XCode console reports this while file writing is going on (the lag feels like it happens for about a second or 2 and not the 200ms implied here):
THREAD WARNING: ['File'] took '93.378906' ms. Plugin should use a background thread.
THREAD WARNING: ['File'] took '125.793945' ms. Plugin should use a background thread.
What can I do to avoid the lag? How can I diagnose where the lag is happening?
Wrapping up the file writing operations with setTimeout does not prevent the main thread from getting blocked, where did you get that? It just delays the execution of the wrapped function, which in your case doesn't help you at all.
Nevertheless, I don't even think this is your real problem, because the file plugin's write operation is already wrapped up for execution in a background thread, which tells you the linked line from the iOS plugin source code.
My guess is there is some other stuff happening, that blocks your UI thread. Which functions from the plugin are you calling exactly? Try to debug/profile the whole process, when the UI lag occurrs, for example in Safari Remote Debugger.
If that doesn't help you, you should post more specific code which could give some hints about what is happening and what the problem could be.
I've created a complex JavaScript web app. It works very well and is fast. But I've noticed that Firefox is continuously using the CPU while the app is open in the browser window but not doing anything. I haven't programmed in any setIntervals, setTimeouts, automatic regular requests to the server - nothing. The only thing it has is the GUI, which is already instantiated and sitting there doing nothing (since the last interaction with the user), and the event handlers which are waiting, attached to various GUI controls. Just to make sure, I used the profiler in Firebug and it confirmed that there was no activity to profile.
I did have 3 FF add-ons running: Avast Online Security, Firebug, and Web Developer. I have disabled these, and it seems to have reduced the CPU useage from say 4-5% to 1-2%. I know this is low, but considering I have only one tab open with my app in it, I would like to know where that 1-2% is being used. The memory consumption is not increasing (it fluctuates, but doesn't increase over time). I have done some quick checks with IE (9) but the CPU usage tends to stay at 0%.
I can't provide any code or solid starting points, but I just thought someone might have some ideas.
We have developed a Samsung Smart TV app for the 2011 & 2012 platforms. The app is HTML/JavaScript based. Normally the app is performing well, but after exiting the app becomes very slow, by a factor of six. The measured JS execution times are only slightly slower, but the HTML elements are rendered much slower to the screen. This behavior happens on all devices (TV and Blu-Ray Player devices with Smart TV Platform).
The exit is realized by executing the JS command
var widgetAPI = new Common.API.Widget();
widgetAPI.sendExitEvent();
The app behaves the same (i.e. becomes slower after starting again) when using the command
widgetAPI.sendReturnEvent();
(which returns the user to the Smart Hub instead of exiting completely). Through trial and error I discovered that making the app crash on purpose solves the problem - this results in an identical behaviour to the user as calling the sendExitEvent method. However, it is not a very clean method, and furthermore I would prefer to use the sendReturnEvent command.
How can I return the user to the Smart Hub programatically so that the app does not get slower when starting it again?
I hope somebody has some first-person experience and advice regarding this. I have tried to eliminate possible JS memory leak sources (using JS programming best practices and advice from Samsung), but that has not remedied the problem.
I solved the problem using two actions:
Instead of simply calling widgetAPI.sendReturnEvent() I redirect the user to a new page exit.html (using window.location.href), which is almost empty, except for an onload handler, which calls the following commands (which are equivalent to widgetApi.sendReadyEvent() and widgetApi.sendReturnEvent() but without needing to include the Widget.js file)
curWidget.setPreference("ready","true");
curWidget.setPreference("return","true");
Commenting out all alert commands. Apparently calling alert leaks memory when used several times so that the accumulated garbage is not collected from the memory when exiting the app, causing it to be slower after restart
Only applying the both methods seemed to fix the issue. Presumably the app accumulates memory leaks causing the app being slow after restart
1) on the document level (despite our efforts to follow all guidelines to prevent them), which are then purged after loading another HTML file.
2) on a global level, caused by calling alert
We stumbled on the usual Friday afternoon bug...
We have a .NET 2.0 WinForms app that uses the WebBrowser control (deployed on XP tablet edition, with latest IE 7). At some point in a page, we are hiding a div and setting a textbox value using some JavaScript. At that point, the operation is working (text appears in the textbox), but the complete window is now frozen. Minimizing/maximizing the window does not respond, etc: it appears that windows messages are not being processed anymore.
If I click anywhere outside of this window (taskbar, another open window), the previously frozen window is now working properly. I redo the same operation, locking occurs again. This is systematic and can be reproduced on this particular machine anytime.
We cannot reproduce it internally using a variety of machines.
On the same machine, if I navigate to the same page and perform the same operation directly with IE 7, everything is working fine... very frustrating.
Any idea on what could cause this behaviour? what to check for? Apparently no JavaScript error is thrown by the page.
Thanks for any ideas or pointers
The .NET 2.0 WebBrowser for Windows Forms is buggy; we've ran into so many different bugs in the implementation, including some interop errors that cause crashing AccessViolationExceptions, that we're now moving away from embedded IE and using Mozilla.
I hate to be a pessimist, but the embeddable IE control is just junk.
You might want to look into Mono.WebBrowser control. Same managed programming interface, but is implemented with the Gecko engine from Firefox and an alternate implementation with the WebKit engine from Chrome and Safari.
Another alternative is to skip the .NET 2.0 WebBrowser wrapper and use the ActiveX IE control directly via mshtml interfaces. Unfortunately, there are even a few bugs in the generated mshtml wrapper.
Bottom line: I'd recommend Mono.WebBrowser.