Crash: Application crashes on uploading a large image
Summary:
The application crashes on uploading a very large image. In this case, the image size was 28.69MB.
Steps to reproduce:
- Find an image which has a large size.
- Try uploading it.
System logs:
java.lang.RuntimeException: Canvas: trying to draw too large(192000000bytes) bitmap.
2020-02-02 05:35:10.603 30429-30429/fr.free.nrw.commons.beta E/AndroidRuntime: FATAL EXCEPTION: main
Process: fr.free.nrw.commons.beta, PID: 30429
java.lang.RuntimeException: Canvas: trying to draw too large(192000000bytes) bitmap.
at android.view.DisplayListCanvas.throwIfCannotDraw(DisplayListCanvas.java:229)
at android.view.RecordingCanvas.drawBitmap(RecordingCanvas.java:98)
at android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:545)
at android.widget.ImageView.onDraw(ImageView.java:1360)
at android.view.View.draw(View.java:20238)
at android.view.View.updateDisplayListIfDirty(View.java:19113)
at android.view.View.draw(View.java:19966)
at android.view.ViewGroup.drawChild(ViewGroup.java:4337)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4114)
at android.view.View.updateDisplayListIfDirty(View.java:19104)
at android.view.View.draw(View.java:19966)
at android.view.ViewGroup.drawChild(ViewGroup.java:4337)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4114)
at android.view.View.draw(View.java:20241)
at androidx.viewpager.widget.ViewPager.draw(ViewPager.java:2426)
at android.view.View.updateDisplayListIfDirty(View.java:19113)
at android.view.View.draw(View.java:19966)
at android.view.ViewGroup.drawChild(ViewGroup.java:4337)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4114)
at android.view.View.updateDisplayListIfDirty(View.java:19104)
at android.view.View.draw(View.java:19966)
at android.view.ViewGroup.drawChild(ViewGroup.java:4337)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4114)
at android.view.View.updateDisplayListIfDirty(View.java:19104)
at android.view.View.draw(View.java:19966)
at android.view.ViewGroup.drawChild(ViewGroup.java:4337)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4114)
at android.view.View.updateDisplayListIfDirty(View.java:19104)
at android.view.View.draw(View.java:19966)
at android.view.ViewGroup.drawChild(ViewGroup.java:4337)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4114)
at android.view.View.updateDisplayListIfDirty(View.java:19104)
at android.view.View.draw(View.java:19966)
at android.view.ViewGroup.drawChild(ViewGroup.java:4337)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4114)
at android.view.View.updateDisplayListIfDirty(View.java:19104)
at android.view.View.draw(View.java:19966)
at android.view.ViewGroup.drawChild(ViewGroup.java:4337)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4114)
at android.view.View.draw(View.java:20241)
at com.android.internal.policy.DecorView.draw(DecorView.java:784)
at android.view.View.updateDisplayListIfDirty(View.java:19113)
at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:686)
at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:692)
at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:801)
at android.view.ViewRootImpl.draw(ViewRootImpl.java:3403)
at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:3193)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2562)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1532)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7406)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1092)
at android.view.Choreographer.doCallbacks(Choreographer.java:888)
at android.view.Choreographer.doFrame(Choreographer.java:819)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1078)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:201)
at android.app.ActivityThread.main(ActivityThread.java:6823)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873)
Device and Android version:
What make and model device: Redmi Note 7 Pro What Android version: Android 9
Commons app version: version: 2.12.2-debug branch: master
Would you like to work on the issue?
Yes. I would like to work on this issue.
Can I work on this issue ?@maskaravivek, @ashishkumar0207
I think we can implement image compression before uploading them, however i doubt it's a good idea from user experience standpoint. I mean the standard carrier networks may take a while to upload such a big file, we can prompt users to select file less than , say 20MB
@kbhardwaj123 One possible solution could be to display a compressed version on the UI and upload the original version
@ashishkumar468 yeah that seems appropriate, we can show a compressed one after the file is picked form the gallery or camera intent, so we need to fix this upload issue if we are about to upload the original one
Tagging @maskaravivek & @nicolas-raoul @misaochan for their inputs.
Sir, I think we should allow the users to upload such high resolution images, as the picture I was trying to upload was also taken from the phone camera. Also, the error exists when we try to inflate the image in the background after it has been retrieved from the media storage. So I think even in other sections like explore and contributions we will get the same error when we will click on the image to view it.
One good solution will be to create a utils file(which resizes the image) to handle this error and using it everywhere where we are trying to inflate the image.
Any updates on this, Sir? @maskaravivek @nicolas-raoul @misaochan
Going to tag @nicolas-raoul for this one, as I am not sure what the Commons community's stance is on extremely large uploads - it will affect whether we choose to compress before or after.
Sir any updates on this? @nicolas-raoul
I think we should support any size that Commons allows us to upload. As the Redmi has 48 megapixels it may hold a lot of details that could be lost if we compressed the image before sending it.
This is not an issue of "uploading" we just tried to show the image in an imageview without decoding it into the bounds of the view.
Seeing as how the log mentions at android.widget.ImageView.onDraw(ImageView.java:1360) I would assume using a DraweeView would fix this.
Where in the upload process fails? Is it trying to show it in UploadMediaDetailsFragment where you add title/description?
If anyone can add a large image to this issue for ease of reproduction that will help whoever takes up this ticket
Indeed, we must support big images at all stages. By the way some people upload all sorts of huge files in various formats via the Upload Wizard web interface, and use the app from time to time, having these files show up in the app's Contributions page. Also, huge images/etc may appear in search. So the app should not crash on any of these files.
I tried to replace the PhotoView with DraweeView as suggested by @macgills and it resolves the problem of crashing. But, now the problem arises that the image does not load in DraweeView because of the URI . Also, the scaling of image is not working as expected.
I have also noticed this issue and managed to found a solution but not sure if it's the best thing to do. I have disabled the hardware acceleration for uploadActivity by adding the android:hardwareAccelerated="false" attribute in Android Manifest File, Now it is working as expected and I am able to upload the image!
@Pratham2305 Yes, you're right, but there are other consequences of using android:hardwareAccelerated="false". So, I think it is not the best solution.
@animeshk08 I unassign for now, but if you are you still working on this, please let us know. If no answer, someone else may be assigned to it. Thanks a lot. :-)
I am not working on this. Please feel free to re-assign :)
Quite frequently reported in v6.0.2. We recently bumped up our target SDK with a few other changes for Android 15; not sure if that's related.
Is there any stack trace that seems to match this?
Yes @nicolas-raoul. Here's one such report:
USER_COMMENT=I'M UPLOADING A PHOTO RELATED TO BUILDINGS EVENING SKY BUT IT KEEPS SHOWING ERROR WHILE UPLOADING IT
APP_VERSION_CODE=1058
APP_VERSION_NAME=6.0.2
ANDROID_VERSION=13
PHONE_MODEL=motorola edge 20 fusion
STACK_TRACE=java.lang.RuntimeException: Canvas: trying to draw too large(324000000bytes) bitmap.
at android.graphics.RecordingCanvas.throwIfCannotDraw(RecordingCanvas.java:266)
at android.graphics.BaseRecordingCanvas.drawBitmap(BaseRecordingCanvas.java:94)
at android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:549)
at android.widget.ImageView.onDraw(ImageView.java:1446)
at android.view.View.draw(View.java:23301)
at android.view.View.updateDisplayListIfDirty(View.java:22168)
at android.view.View.draw(View.java:23032)
at android.view.ViewGroup.drawChild(ViewGroup.java:4541)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4302)
at android.view.View.draw(View.java:23304)
at android.view.View.updateDisplayListIfDirty(View.java:22168)
at android.view.View.draw(View.java:23032)
at android.view.ViewGroup.drawChild(ViewGroup.java:4541)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4302)
at android.view.View.draw(View.java:23304)
at androidx.viewpager.widget.ViewPager.draw(ViewPager.java:2426)
at android.view.View.updateDisplayListIfDirty(View.java:22168)
at android.view.View.draw(View.java:23032)
at android.view.ViewGroup.drawChild(ViewGroup.java:4541)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4302)
at android.view.View.updateDisplayListIfDirty(View.java:22159)
at android.view.View.draw(View.java:23032)
at android.view.ViewGroup.drawChild(ViewGroup.java:4541)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4302)
at
android.view.View.updateDisplayListIfDirty(View.java:22159)
at android.view.View.draw(View.java:23032)
at android.view.ViewGroup.drawChild(ViewGroup.java:4541)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4302)
at android.view.View.updateDisplayListIfDirty(View.java:22159)
at android.view.View.draw(View.java:23032)
at android.view.ViewGroup.drawChild(ViewGroup.java:4541)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4302)
at android.view.View.updateDisplayListIfDirty(View.java:22159)
at android.view.View.draw(View.java:23032)
at android.view.ViewGroup.drawChild(ViewGroup.java:4541)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4302)
at android.view.View.updateDisplayListIfDirty(View.java:22159)
at android.view.View.draw(View.java:23032)
at android.view.ViewGroup.drawChild(ViewGroup.java:4541)
at
android.view.ViewGroup.dispatchDraw(ViewGroup.java:4302)
at android.view.View.draw(View.java:23304)
at com.android.internal.policy.DecorView.draw(DecorView.java:854)
at android.view.View.updateDisplayListIfDirty(View.java:22168)
at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:689)
at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:695)
at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:793)
at android.view.ViewRootImpl.draw(ViewRootImpl.java:5064)
at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:4773)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3983)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2580)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:9586)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1231)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1239)
at android.view.Choreographer.doCallbacks(Choreographer.java:899)
at
android.view.Choreographer.doFrame(Choreographer.java:832)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1214)
at android.os.Handler.handleCallback(Handler.java:984)
at android.os.Handler.dispatchMessage(Handler.java:104)
at android.os.Looper.loopOnce(Looper.java:238)
at android.os.Looper.loop(Looper.java:357)
at android.app.ActivityThread.main(ActivityThread.java:8194)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:957)
I have disabled the hardware acceleration for uploadActivity by adding the android:hardwareAccelerated="false" attribute in Android Manifest File, Now it is working as expected and I am able to upload the image!
Did it originate from here? 🤔 If yes, it's better to revert the change in the manifest and disable the animation added recently until we find the right solve. Seems like those changes broke the flow in v6.0.2. @rohit9625 what are your thoughts on this?
It could be, but I don't think so because the error was reported 6 years ago as well, when we already had hardware acceleration disabled for UploadActivity. However, it is worth trying after disabling. From the logs, it seems that the image was quite large (324 MB). How could an image be this large?
Can you reproduce this issue, @RitikaPahwa4444? If yes, please share the image and repro steps.
The image size indeed seems quite big and that was the first thing even I noticed. But there are several crash reports lined up this time. My only concern is that it surfaced up again after we released those changes. So I would prefer to revert in this release until we find the solve.
If it's because hardware acceleration, then this could be the reason:
- Hardware acceleration = faster UI rendering, but strict GPU limits.
- Software rendering = slower, but tolerant of large offscreen bitmaps.
So, either we can disable the harware acceleration or resize the image while rendering. I can try this if I found this large image on internet.
The image size indeed seems quite big and that was the first thing even I noticed. But there are several crash reports lined up this time. My only concern is that it surfaced up again after we released those changes. So I would prefer to revert in this release until we find the solve.
Okay, I'll try to repro this issue and report the findings today. Also, if resizing the image while rendering solves the problem. Then we are good to go :)
I see 141 MB as well in one of the reports. The images shot with my 50 MP camera do take > 10 MB per image on my device, not sure about newer cameras with higher resolution. I'll share the minimum number once I go through all the reports again.
I see 141 MB as well in one of the reports. The images shot with my 50 MP camera do take > 10 MB per image on my device, not sure about newer cameras with higher resolution. I'll share the minimum number once I go through all the reports again.
Oh, so this issue can be repeated with multiple images as well? I thought it's just one image with size 144 mb.
I can only find image files of 100MB max. I tried uploading two 100MB files simultaneously to repeat the crash on my end, but the UploadActivity got closed without any crash logs, and the app navigated to the Contributions screen.
https://github.com/user-attachments/assets/7a858b87-c7c9-4382-824c-2c51e9d5c682
When testing on a physical device, the app is crashing completely but I couldn't see any logs and that ACRA dialog also doesn't appear.
Tested with android:hardwareAccelerated="false" for UploadActivity but still the same behavior. What about limiting the large image uploads or resizing them to the maximum acceptable size. Uploading 100MB files are not very common I guess. What do you think, @RitikaPahwa4444?