mono / SkiaSharp

SkiaSharp is a cross-platform 2D graphics API for .NET platforms based on Google's Skia Graphics Library. It provides a comprehensive 2D API that can be used across mobile, server and desktop models to render images.
MIT License
4.53k stars 540 forks source link

[BUG] NullReferenceException: Object reference not set to an instance of an object in SKGLTextureViewRenderer.OnDrawFrame (Javax.Microedition.Khronos.Opengles.IGL10 gl) #1723

Open thisisthekap opened 3 years ago

thisisthekap commented 3 years ago

Description

Heavily reported by our production monitoring, not able to reproduce locally.

System.NullReferenceException: Object reference not set to an instance of an object
  at SkiaSharp.Views.Android.SKGLTextureViewRenderer.OnDrawFrame (Javax.Microedition.Khronos.Opengles.IGL10 gl) [0x0008a] in <2240341f42164adf9675613a7d38e6a2>:0
  at SkiaSharp.Views.Android.GLTextureView+GLThread.GuardedRun () [0x003bd] in <2240341f42164adf9675613a7d38e6a2>:0
  at SkiaSharp.Views.Android.GLTextureView+GLThread.Run () [0x00028] in <2240341f42164adf9675613a7d38e6a2>:0
  at System.Threading.ThreadHelper.ThreadStart_Context (System.Object state) [0x00014] in <49badae49cda4201a817f1b87a55a469>:0
  at System.Threading.ExecutionContext.RunInternal (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00071] in <49badae49cda4201a817f1b87a55a469>:0
  at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00000] in <49badae49cda4201a817f1b87a55a469>:0
  at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state) [0x0002b] in <49badae49cda4201a817f1b87a55a469>:0
  at System.Threading.ThreadHelper.ThreadStart () [0x00008] in <49badae49cda4201a817f1b87a55a469>:0

Code

Using SKGLView as a drawing canvas.

Basic Information

Detailed IDE/OS information (click to expand) ``` PASTE ANY DETAILED VERSION INFO HERE ```
mattleibow commented 3 years ago

I think it may be related to the drawing happening but for some reason the surface is not there.

This could be if the view is rendering, but then is removed from the hierarchy or disposed mid-render. As a result, we have a context, but the context does not have any surface. In the end, the null surface is trying to create a canvas, which blows up.

Maybe see if there is a way to cancel rendering when the view is no longer used? Not sure exactly your app flow, but see if it helps is there is some way to disconnect the render and/or set the render mode to not looping.

That is the only reason I can see that it was told there is a surface, but it was gone by the time skia wanted to start working.

thisisthekap commented 3 years ago

@mattleibow Thanks for the suggestions, I will definitely give them a try.

What exactly do you mean by "disconnect the render loop"?

thisisthekap commented 3 years ago

@mattleibow Could you please clarify?

mattleibow commented 3 years ago

Hi, sorry. I see I typed the reply on my phone, but it never actually went through.

I meant you can try do a HasRenderLoop=false when the page is disappearing. This should shut down the render loop thread. If that resolves it, then I can investigate some more. The issue could be that the frame draw has started but actually is killed mid-way through.

If this fixes it then I can see if I can add more guards.

Huaba93 commented 3 years ago

@mattleibow we have the same problem. In the last 30 days it caused about 1k crashes for 300 different users. It is also the most common reason for crashes on Android for us.

Most effected devices: Y7 Prime 2019 HUAWEI Y7s Honor 8X Max

Setting HasRenderLoop=false on disappearing/sleep did not change anything. Unfortunately, we can't reproduce the problem ourselves, so I don't know if abandoning HasRenderLoop would fix it.

Xamarin Exception Stack:
System.NullReferenceException: Object reference not set to an instance of an object
  at SkiaSharp.Views.Android.SKGLTextureViewRenderer.OnDrawFrame (Javax.Microedition.Khronos.Opengles.IGL10 gl) [0x0008a] in <2240341f42164adf9675613a7d38e6a2>:0
  at SkiaSharp.Views.Android.GLTextureView+GLThread.GuardedRun () [0x003bd] in <2240341f42164adf9675613a7d38e6a2>:0
  at SkiaSharp.Views.Android.GLTextureView+GLThread.Run () [0x00028] in <2240341f42164adf9675613a7d38e6a2>:0
  at System.Threading.ThreadHelper.ThreadStart_Context (System.Object state) [0x00014] in <90373b3274ec474892629de4358854a7>:0
  at System.Threading.ExecutionContext.RunInternal (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00071] in <90373b3274ec474892629de4358854a7>:0
  at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00000] in <90373b3274ec474892629de4358854a7>:0
  at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state) [0x0002b] in <90373b3274ec474892629de4358854a7>:0
  at System.Threading.ThreadHelper.ThreadStart () [0x00008] in <90373b3274ec474892629de4358854a7>:0
Huaba93 commented 3 years ago

@mattleibow SKSurface.Create can return null on purpose.

Returns the new surface if it could be created and the configuration is supported, otherwise null.

Src: https://docs.microsoft.com/en-us/dotnet/api/skiasharp.sksurface.create?view=skiasharp-2.80.2#SkiaSharp_SKSurface_Create_SkiaSharp_GRContext_System_Boolean_SkiaSharp_SKImageInfo_System_Int32_

So this part could be causing the crash:

https://github.com/mono/SkiaSharp/blob/95c296bd9e8301205c7136de5670681fd1f24396/source/SkiaSharp.Views/SkiaSharp.Views.Android/SKGLTextureViewRenderer.cs#L88-L89

thisisthekap commented 3 years ago

HasRenderLoop=false did not solve our issue as well. @mattleibow what do you think about the suggestion of @Huaba93 to add a null check?

thisisthekap commented 2 years ago

@mattleibow Would the null check for the result of SKSurface.Create be a viable option (as suggested by https://github.com/mono/SkiaSharp/issues/1723#issuecomment-945391399)?

thisisthekap commented 2 years ago

@mattleibow I tried to build skiasharp myself. Without success. When executing the target externals-download, keep getting a "method not found" error:


========================================
externals-download
========================================
Downloading '_nativeassets' version '0.0.0-branch.main.179'...
An error occurred when executing task 'externals-download'.
Error: One or more errors occurred. (Method not found: 'System.Threading.Tasks.Task`1<System.Collections.Generic.IEnumerable`1<System.String>> NuGet.Packaging.PackageReaderBase.CopyFilesAsync(System.String, System.Collections.Generic.IEnumerable`1<System.String>, NuGet.Packaging.Core.ExtractPackageFileDelegate, NuGet.Common.ILogger, System.Threading.CancellationToken)'.)
        Method not found: 'System.Threading.Tasks.Task`1<System.Collections.Generic.IEnumerable`1<System.String>> NuGet.Packaging.PackageReaderBase.CopyFilesAsync(System.String, System.Collections.Generic.IEnumerable`1<System.String>, NuGet.Packaging.Core.ExtractPackageFileDelegate, NuGet.Common.ILogger, System.Threading.CancellationToken)'.
thisisthekap commented 2 years ago

@mattleibow This issue keeps to be the top reason for crashes for all of our android apps. As I am unfortunately not able to do a custom build myself, your help is very much appreciated. I would be happy to do a PR as well, but without the ability to build the repository on my side, I do not want to propose a code change.

wouterst79 commented 2 years ago

I'm now seeing crashes with the same stack trace - exclusively on Y7 Prime 2019

Crashes all happen after "2seconds" (according to appcenter).

SKGLTextureViewRenderer.OnDrawFrame (Javax.Microedition.Khronos.Opengles.IGL10 gl)
GLTextureView+GLThread.GuardedRun ()
GLTextureView+GLThread.Run ()
ThreadHelper.ThreadStart_Context (System.Object state)
ExecutionContext.RunInternal (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx)
ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx)
ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state)
ThreadHelper.ThreadStart ()

This code is running on Xamarin.Android (no Xamarin.Forms involved) - as far as I can tell, the Renderloop is a Xamarin Forms feature. I've tried to find a device farm with any of the mentioned devices, but no luck.

I've looked through my event logs, and I do see logs from Huawei devices, just none with a device type containing Y7. I'm thinking I'll exclude that device from being supported from the Play Store.

@mattleibow - what's the next step in the investigation here?

wouterst79 commented 2 years ago

I have another set of these (also on Y7 Prime 2019), but now they appear sometimes after 5 seconds, and sometimes after 8.

SKGLTextureViewRenderer.OnDrawFrame (Javax.Microedition.Khronos.Opengles.IGL10 gl)
GLTextureView+GLThread.GuardedRun ()
GLTextureView+GLThread.Run ()
ThreadHelper.ThreadStart_Context (System.Object state)
ExecutionContext.RunInternal (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx)
ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx)
ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state)
ThreadHelper.ThreadStart ()
Picao84 commented 1 year ago

Did anyone find any way to fix this? I've a tried a lot on mine Xamarin Forms, but looking at the stack trace it does not look like the issue is with my code, as the crash happens even before the OnPaintSurface method is called?