none
[UWP] OnSuspending throws unexpected error in Windows 10 version 1809 and later

    Question

  • Hi,
    Looking at the health report for my app in the Dev Center, I'm seeing increasing numbers of failures of the form 

    stowed_exception_system.exception_8000ffff_myappname.exe!myappname::app::_onsuspending_d__6.movenext

    However, this failure has only started to appear with Windows version 1809 (and the insider versions), where it accounts for over half the total failures. If I filter to Windows version 1803, then the percentage of crash-free devices is at 99.8%, but for build 1809 it is down at 80%, largely due to this specific failure.

    Therefore, the way the OnSuspending event is handled must have changed in Windows version 1809. I feel that maybe this is a bug whereby the deadline is not being properly reported in the OnSuspending arguments or the suspending handler is simply being cut off before the deadline. I can't see any reason for this error from my code as all I do in the suspending handler is get a deferral, invoke some cleanup code without awaiting, then check to see if more than 400ms are available until the deadline and if so do an await Task.delay(200) before calling deferral.Complete(). (To give the cleanup code a chance to finish if possible).

    Please can someone tell me if the new behaviour I'm observing is intentional (and if so please document it), or is it a bug?

    (I don't yet have the 1809 update myself so I can't test it, plus I find it hard to test the Suspending event effectively).

    Thanks.


    • Edited by Ben48 Monday, November 12, 2018 8:03 PM
    Monday, November 12, 2018 8:02 PM

All replies

  • Hi,

    Well, I could not tell something about this as I haven't test about this. Could you please share me a code snippet about what you are doing in the OnSuspending events? I need a demo to reproduce this issue on Build 1809 so that I could take a look at it.

    Best regards,

    Ry


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Tuesday, November 13, 2018 3:00 AM
    Moderator
  • Hi Roy,

    Thanks for the reply. The code is basically like this

    private async void OnSuspending(object sender, SuspendingEventArgs e) {
                var deferral = e.SuspendingOperation.GetDeferral();
                try {
                    foreach (var view in CoreApplication.Views) {
                        var task = view.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => {
                            System.Diagnostics.Debug.WriteLine("Run some cleanup code here");
                        });
                    }
                } catch (Exception) { }
                var timeRemaining = e.SuspendingOperation.Deadline.Subtract(DateTimeOffset.Now);
                if(timeRemaining.TotalMilliseconds > 400) {
                    await Task.Delay(200); //This should give a chance of closing some file handles
                }
                deferral.Complete();
            }

    Tuesday, November 13, 2018 8:21 AM
  • Probably you have to wait when cleanup tasks will complete their work

                var deferral = e.SuspendingOperation.GetDeferral();
    
                using (var runningTasks = new CountdownEvent(1))
                {
                    var currentView = CoreApplication.GetCurrentView();
                    
                    foreach (var view in CoreApplication.Views)
                    {
                        if (view != currentView)
                        {
                            runningTasks.AddCount();
    
                            await view.Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
                            {
                                try
                                {
                                    // Cleanup
                                }
                                finally
                                {
                                    runningTasks.Signal();
                                }
                            });
                        }
                    }
    
                    // Cleanup for main view
    
                    runningTasks.Signal();
    
                    runningTasks.Wait(e.SuspendingOperation.Deadline - DateTimeOffset.Now - TimeSpan.FromMilliseconds(5));
    
                    // Request extended execution session if needed
                }
    
                deferral.Complete();


    Wednesday, November 14, 2018 12:05 PM
  • Hi,

    Any updates?

    Does @Username already in use's reply make sense?

    Best regards,

    Roy


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, December 6, 2018 10:03 AM
    Moderator
  • Thanks @Username already in use for trying to help, but that code as it stands is not a good idea. The Suspending event runs on the main UI thread so calling Wait() will block the main UI thread.

    I haven't had time to investigate yet. One thing I realised is that my try/catch handler is a bit useless since I'm not awaiting the tasks - I perhaps either need to use TryRunAsync or add a ContinueWith to the tasks to discard any exception. I will post an update when I've investigated further.

    Friday, December 7, 2018 9:01 PM
  • Thanks @Username already in use for trying to help, but that code as it stands is not a good idea. The Suspending event runs on the main UI thread so calling Wait() will block the main UI thread.

    I haven't had time to investigate yet. One thing I realised is that my try/catch handler is a bit useless since I'm not awaiting the tasks - I perhaps either need to use TryRunAsync or add a ContinueWith to the tasks to discard any exception. I will post an update when I've investigated further.


    At that moment all the work in main thread will be completed and it will be safe to block it, but if you think that asynchronous execution is better way, CountdownEvent can be replaced by collection of TaskCompletionSources and awaiting Task.WhenAll.
    Wednesday, December 12, 2018 6:58 PM
  • Ok, maybe that's true but I think I'd prefer not to block because I have multiple views and they sometimes run stuff on the main thread etc.

    I thought I would post an update on my progress with investigating this.

    Upon investigation I found that the tasks which tried to run on different view threads sometimes didn't complete at all. In fact it seems that the different views are suspended independently. This stumped me for a while as I didn't understand how to do cleanup for the other views. However, I then had a revelation:

    The Suspending event handler is called on the same thread on which the event handler was subscribed (at least if it was subscribed on a UI thread). This actually makes things quite a lot simpler and is a good feature I think (although it is slightly counter-intuitive). But this is not documented anywhere! Please can this be added to the documentation? I also found that the Resuming event behaves in the same way, even though the documentation says the resuming event is not called on the UI thread. Can this be documented as well? So I simplified my Suspending handler to the following, added separately for each view.

    private async void App_Suspending(object sender, Windows.ApplicationModel.SuspendingEventArgs e) {
                if (!Dispatcher.HasThreadAccess) { //Just in case since documentation is lacking
                    return;
                }
                var deadline = e.SuspendingOperation.Deadline;
                HandleSuspend(); //Synchronous call
                var timeRemaining = deadline.Subtract(DateTimeOffset.Now);
                if (timeRemaining.TotalMilliseconds > 400) {
                    var deferral = e.SuspendingOperation.GetDeferral();
                    await Task.Delay(200);//This should give a chance of closing some file handles
                    deferral.Complete();
                }
            }
    However, this hasn't significantly changed the number of errors I am seeing on version 1809. I have fewer Suspending_MoveNext errors, but I still have quite a lot of hang_quiesce errors, and a lot more unknown_function errors. I'm wondering if perhaps the app is being terminated while suspended or something due to memory usage maybe. But I was never able to reproduce an error like this on my PC. Or maybe the Task.Delay is an issue. I guess my next experiment would be to take that out, but I don't like doing experiments on my live app, although this seems to be the only way to diagnose the problem. I haven't had any users complaining though, so perhaps another explanation is that the error is occurring when the app is being closed by the user, in which case they wouldn't care anyway. Also, my app is registered for prelaunching so I wonder if the error could be occurring whilst it's in the prelaunched state. Any ideas would be welcome.



    • Edited by Ben48 Monday, December 17, 2018 7:09 PM
    Monday, December 17, 2018 7:08 PM
  • A further follow-up: I think I finally found the reason for the vastly increased crashes in 1809 and it is a bug in 1809 but it's only indirectly related to suspending. My app still supports the 1507 Windows release therefore it is using the Windows.ApplicationModel.Store namespace for add-on purchases. If the user is running Windows 10 version 1809, then the LicenseInformation.LicenseChanged handler is fired continually every 2 seconds (this did not happen in version 1803). It even seems to be called when the app is suspended which can cause it to crash. I don't know if you have to have purchased an addon or not for this to happen as it's quite difficult to test (the bug does not occur when using the CurrentAppSimulator). This is a bit annoying, and it would be nice if it was fixed, although I will be dropping support for anything before the anniversary update soon and as part of that I will update to using the new StoreContext which hopefully doesn't have this bug.
    Wednesday, December 19, 2018 8:57 PM