bug: Crash / restart due to OOM, when capturing a photo via <input> element
See original GitHub issueBug Report
The app crashes/restarts when taking photos via file-input element (intermittently). Probably due to an out of memory (OOM) issue, where the OS tells the app to free memory.
Capacitor Version
Using Capacitor 1.2.1 (expand for npx capacitor doctor command)
$ npx capacitor doctor
💊 Capacitor Doctor 💊
Latest Dependencies:
@capacitor/cli: 1.4.0
@capacitor/core: 1.4.0
@capacitor/android: 1.4.0
@capacitor/ios: 1.4.0
Installed Dependencies:
@capacitor/cli 1.2.1
@capacitor/core 1.2.1
@capacitor/ios 1.2.1
@capacitor/android 1.2.1
[success] Android looking great! 👌
Found 1 Capacitor plugin for ios:
cordova-plugin-nativestorage (2.3.2)
[success] iOS looking great! 👌
Affected Platform(s)
- iOS
-
- Android not affected*
-
- Electron not affected*
-
- Web not affected*
Current Behavior
Take a photograph using the camera on iOS, via an html input element. This happens ~1/5 times on an iPhone 8 (with 2 gb ram and 20 gb of free disk storage).
When checking the logs when connected to XCode this message is shown:
2019-12-17 14:03:20.020185+0100 App[26652:8475493] Received memory pressure event 1 vm pressure 0
Received memory pressure event 1 vm pressure 0
2019-12-17 14:04:06.478996+0100 App[26652:8475493] Received memory pressure event 4 vm pressure 1
Received memory pressure event 4 vm pressure 1
Expected Behavior
Camera will return to the webview, and the input element will have the files
property populated. This works ~4/5 times.
Sample Code & Reproduction Steps
<p>
1. Open a bunch of other apps on the phone (running in the background).
2. Try taking photos repeatedly using this html snippet.
3. The webview will crash/reload (the actual iOS app doesn't crash).
</p>
<input type='file' multiple accept='image/*'>
Reproduction Steps
See steps in sample code above.
Other Technical Details
n/a
Other Information
We’ve recently ported our app over from Cordova to Capacitor. This code has worked flawlessly for several years and tens of thousands of users. In other words, this technique for grabbing photos via the input element has been robust.
Overall we’re very happy with the move to Capacitor! But this issue has appeared after the migration.
Maybe there is some type of memory tuning that Cordova was doing on its web view, that Capacitor isn’t doing? (just a guess)
This seems to be what Capacitor is doing right now:
override public func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
-
Does iOS send this message to all apps? In that case it would be better if Capacitor didn’t jumped forward offering to trash (calling super), if background apps could release stuff.
-
Can we somehow track that the camera is in the foreground and skip calling super in that case?
-
Would it be possible to detect that the webview isn’t in the foreground (and infer that the camera is running via an input element, therefore we shouldn’t be quick to dispose of any resources)?
-
Would it be possible to adjust
webViewWebContentProcessDidTerminate
so that the JS-layer could be aware of the restart, i.e. know that the app crashed and restarted. Even though we wouldn’t know the reason, at least we’d know that it happened.
After looking through the Cordova source I noticed that this is how they handle this: https://github.com/apache/cordova-ios/blob/master/CordovaLib/Classes/Public/CDVViewController.m#L578
It isn’t obvious to me why we’ve never seen this issue under Cordova, since their handling seems similar (since I don’t think any plugin would return hasPendingOperation
only because an input element has triggered the camera). But I suspect there are more factors in play here besides just the call to didReceiveMemoryWarning
.
Also, I’m guessing the restart may be due to webViewWebContentProcessDidTerminate
being called in CAPBridgeViewController
.
Issue Analytics
- State:
- Created 4 years ago
- Reactions:1
- Comments:7 (6 by maintainers)
For anyone else who comes across this problem, for me it was caused by a serious memory leak in iOS 12+ when using canvas the resize the captured image: https://github.com/openlayers/openlayers/issues/9291. Fortunately there is a simple workaround - set the canvas dimensions to zero to “dispose” of it.
I am experiencing this same intermittent reloading of the webview after capturing photos via an
<input>
element - it was very difficult to diagnose, because the webview reloaded so quickly I didn’t notice it (seems like #2379 would help with this). Our users are experiencing data loss due to this issue so it would be great to find a solution, thought I understand it’s probably due to some webkit memory leak.Edit: I like @sandstrom 's suggestion of asking plugins if it’s ok to purge memory.