apache / cordova-plugin-camera

Apache Cordova Plugin camera
https://cordova.apache.org/
Apache License 2.0
966 stars 1.55k forks source link

App and device crash on Android 11 after about 200 photos #710

Closed ita33 closed 3 years ago

ita33 commented 3 years ago

Bug Report

Problem

After taking somewhere between 195 to 218 photos on Android 11, the app (and sometimes the entire device) will crash. Performed this test several times on same device running Android 10 and able to surpass 1,000 photos without crashing.

What is expected to happen?

The camera should continue functioning without crashing the application or device

What does actually happen?

The app crashes. Root error appears to be an out of memory error which matches all the symptoms; camera getting slower and slower until crash, app not working properly until device re-booted. If user continues to press camera capture button, while the screen is frozen, the device will sometimes crash.

Information

Stack trace:

02-15 18:02:36.390 13006 13257 E AndroidRuntime: Process: com.google.android.GoogleCamera, PID: 13006 02-15 18:02:36.390 13006 13257 E AndroidRuntime: java.lang.OutOfMemoryError: Failed to allocate a 1981728 byte allocation with 550752 free bytes and 537KB until OOM, target footprint 536870912, growth limit 536870912 02-15 18:02:36.390 13006 13257 E AndroidRuntime: at java.util.Arrays.copyOf(Arrays.java:3161) 02-15 18:02:36.390 13006 13257 E AndroidRuntime: at java.io.ByteArrayOutputStream.grow(ByteArrayOutputStream.java:118) 02-15 18:02:36.390 13006 13257 E AndroidRuntime: at java.io.ByteArrayOutputStream.ensureCapacity(ByteArrayOutputStream.java:93) 02-15 18:02:36.390 13006 13257 E AndroidRuntime: at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:153) 02-15 18:02:36.390 13006 13257 E AndroidRuntime: at qlc.write(PG:2) 02-15 18:02:36.390 13006 13257 E AndroidRuntime: at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82) 02-15 18:02:36.390 13006 13257 E AndroidRuntime: at java.io.BufferedOutputStream.write(BufferedOutputStream.java:126) 02-15 18:02:36.390 13006 13257 E AndroidRuntime: at ngk.b(PG:1) 02-15 18:02:36.390 13006 13257 E AndroidRuntime: at ngl.write(PG:7) 02-15 18:02:36.390 13006 13257 E AndroidRuntime: at com.google.common.io.ByteStreams.copy(PG:4) 02-15 18:02:36.390 13006 13257 E AndroidRuntime: at com.google.android.libraries.camera.exif.ExifInterface.h(PG:4) 02-15 18:02:36.390 13006 13257 E AndroidRuntime: at ilz.R(PG:7) 02-15 18:02:36.390 13006 13257 E AndroidRuntime: at icg.run(PG:87) 02-15 18:02:36.390 13006 13257 E AndroidRuntime: at ibb.run(PG:2) 02-15 18:02:36.390 13006 13257 E AndroidRuntime: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 02-15 18:02:36.390 13006 13257 E AndroidRuntime: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 02-15 18:02:36.390 13006 13257 E AndroidRuntime: at java.lang.Thread.run(Thread.java:923) 02-15 18:02:36.390 13006 13257 E AndroidRuntime: at msl.run(PG:2) 02-15 18:02:36.390 13006 13257 E AndroidRuntime: Suppressed: java.lang.OutOfMemoryError: Failed to allocate a 1981728 byte allocation with 542240 free bytes and 529KB until OOM, target footprint 536870912, growth limit 536870912 02-15 18:02:36.390 13006 13257 E AndroidRuntime: at java.util.Arrays.copyOf(Arrays.java:3161) 02-15 18:02:36.390 13006 13257 E AndroidRuntime: at java.io.ByteArrayOutputStream.grow(ByteArrayOutputStream.java:118) 02-15 18:02:36.390 13006 13257 E AndroidRuntime: at java.io.ByteArrayOutputStream.ensureCapacity(ByteArrayOutputStream.java:93) 02-15 18:02:36.390 13006 13257 E AndroidRuntime: at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:153) 02-15 18:02:36.390 13006 13257 E AndroidRuntime: at qlc.write(PG:2) 02-15 18:02:36.390 13006 13257 E AndroidRuntime: at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82) 02-15 18:02:36.390 13006 13257 E AndroidRuntime: at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140) 02-15 18:02:36.390 13006 13257 E AndroidRuntime: at java.io.FilterOutputStream.close(FilterOutputStream.java:179) 02-15 18:02:36.390 13006 13257 E AndroidRuntime: at ngl.close(PG:4) 02-15 18:02:36.390 13006 13257 E AndroidRuntime: at com.google.android.libraries.camera.exif.ExifInterface.h(PG:3)

Command or Code

Environment, Platform, Device

Android 11 on a Samsung S20 and a Google Pixel 4XL The camera will go beyond 1,000 consecutive photos without crashing the app on Android 6 thru Android 10 (same devices running Android 10; different devices running Android 6 thru 9)

Version information

cordova 10.0.0 cordova android 9.0.0 cordova-plugin-camera 5.0.1 Have also tested dev version of cordova-plugin-camera 5.0.2 that included the fix for ticket #665 and the same crash happens. We've been following ticket #665 closely hoping that it would fix this issue, but it did not.

Checklist

breautek commented 3 years ago

As the stack trace indicates, this is not a problem with the camera plugin, but a problem with the Camera app itself.

02-15 18:02:36.390 13006 13257 E AndroidRuntime: Process: com.google.android.GoogleCamera, PID: 13006
...
02-15 18:02:36.390 13006 13257 E AndroidRuntime: at com.google.android.libraries.camera.exif.ExifInterface.h(PG:3)

There isn't anything Cordova can do about this unfortunately. I'd advise searching and reporting bugs on Google Apps on their issue tracker.

Houdhey commented 3 years ago

I'm not sure about that, I met exactly the same problem, we're testing our App on these new devices having Android 11, and my App was working when I take "black photos", with low size, but when I pick photos > 3MB or 4 MB, it crashed. I think this is related to the destinationType property, I'm returning directly the base 64 encoded string and it is very intensive data. There is a warning about this. image

breautek commented 3 years ago

I'm returning directly the base 64 encoded string and it is very intensive data.

There is also nothing Cordova can do about Base64 encoded images. Modern phones can return a very large resolution for images, and these phones can also be paired with low memory resources. Base64 will blow up the size of any binary file by about ~30%. Additionally, it needs to copy that data from native to the webview. This results in high memory usage spikes. Strings in the JS environment are also pass-by-value, so they are furthered copied for every time you pass that string around in your application.

Cordova makes note of this in the example:

/**
 * Warning: Using DATA_URL is not recommended! The DATA_URL destination
 * type is very memory intensive, even with a low quality setting. Using it
 * can result in out of memory errors and application crashes. Use FILE_URI
 * instead.
 */

Using FILE_URI destination is the most efficient ways to work with images.

ita33 commented 3 years ago

@breautek, Thank you very much for your quick response yesterday. Can't thank you and your team enough for all that you do to maintain this plugin. Can you please help us understand something? As a note, we are using FILE_URI as destination... Regarding the initial stack trace we provided on this ticket, you mentioned that the problem is with the device's camera (Google Pixel 4XL) and to reach out to google issue tracker. We've quantity tested this plugin on several Android devices and the crash only happens on Android 11. The stack trace provided was on a Google Pixel 4XL running Android 11 that crashes consistently around 200 photos captured, but the app does not crash on the same device running on Android 10 with over 1,000 photos. Another example... on a Samsung S20 FE running Android 10, we can get to 1,000 photos with no crashes, as well. On the same Samsung S20 FE device running Android 11, it consistently crashes at 55 - 65 photos captured and must completely restart the device for it to function at all again. The stack trace on the Samsung S20 FE is not quite as clear as the one provided on the Google Pixel 4XL. If the same device, using the same camera, running Android 10 does not crash, but the same device running Android 11 does crash, can you please help us understand why the issue is with the device's camera?

breautek commented 3 years ago

We've quantity tested this plugin on several Android devices and the crash only happens on Android 11. The stack trace provided was on a Google Pixel 4XL running Android 11 that crashes consistently around 200 photos captured, but the app does not crash on the same device running on Android 10 with over 1,000 photos

Some background knowledge... This plugin uses something called Intent, which is a process of delegating an action to another app. This is why this plugin doesn't need the Camera permissions to use the Camera APIs because it delegates the usage of the camera APIs to another app, which then passes the result back to the invoker (aka your app).

To be clear, different android devices may have different camera apps installed and different Android versions may different versions of the camera app. For example, the GoogleCamera app states:

Requirements - The latest version of Google Camera only works on Pixel phones running Android 11 and above. Some features are not available on all devices.

Therefore, you running Android 10 on the same device probably means you're running an older version of the GoogleCamera app which may not exhibit your issue. This would probably be useful knowledge to add in the bug ticket for Google. If you view the Google Camera app info, you probably see two different versions. It would be useful to include a version that does not have an issue, and the version that does.

On the same Samsung S20 FE device running Android 11, it consistently crashes at 55 - 65 photos captured and must completely restart the device for it to function at all again.

I can't really explain this, other than perhaps the issue is not so much with the Camera apps but a bug in the OS, but if that were the case, I would expect to see the crashing on any device.

If the issue produces consistently, one thing that could be done to isolate the issue (and potentially point blame to the cordova plugin) is to create two minimal reproduction apps. These app should be deployed on the devices exhibiting the issue.

The first app should be a pure native app, that uses the Camera Intents. Special note here, the android plugin does not use any AndroidX libraries, so I'd recommend ignoring the Note about using the cameraX class or the camera2 class. You can pull code snippets from CameraLauncher class if that helps.

The second app should be a minimal cordova app that produces the issue.

If the native app fails to demonstrate the issue but the minimal cordova app does, I think that's a good enough evidence that say the my original assessment is wrong, and the GoogleCamera crash may just be a side effect of another issue that is occurring (such as a memory leak inside the cordova plugin?). If that's the case, I'll gladly reopen this issue. It would be useful to share those minimal reproduction apps as well.

If you need any assistance in creating these minimal reproduction apps, our Slack can probably help you.

satheeshkumartitan commented 3 years ago

I've also updated the latest plugin 5.0.2, but the same problems occur on Android 10 (device - redmi note 7pro). The plugin 5.0.2. Forcefully close the application once we capture a photo. This happens on some specific devices. Please update the new version I'm waiting for the new version Node -v ----14.16.0 ionic -v ---- 6.13.1 cordova -v----10.0.0 ionic cordova platform add android@9.1.0 npm i @ionic-native/camera@5.33.0 tested and both same crash.

I'm waiting for your response, thanks