May 23, 2014 1:11 pm

Understanding and resolving app crashes and failures in Windows Store apps, part 2: JSON and tiles

This post was written by Gretchen Loihle and Andrew Richards in the Windows Reliability/Windows Error Reporting team.

Welcome to our second post to inform Windows Store app developers about the most common failures being seen in the Windows Error Reporting (WER) telemetry across multiple Windows Store apps, and provide recommendations for how to avoid them. We invite you to read the introductory article for a more thorough discussion about WER and the availability of failure telemetry through the Store dashboard.

In this segment we touch on new failures in a familiar area and introduce some new issues. In particular, we discuss JSON object deserialization, managing unexpected HTTP events, and updating Live Tiles.

Before we begin, note that Microsoft has released the code for .NET 4.5.1 under the Microsoft Reference Source License (MS-RSL), and made it available to browse and download at http://ReferenceSource.microsoft.com. We’ll occasionally reference the affected code, so please feel free to examine the functions shown in the call stacks to see some of the error origins. For more on all this, see these additional resources:

JSON parsing failures

Newtonsoft.Json.dll!Newtonsoft.Json.JsonTextReader.ParseValue

The talented engineers contributing to the Newtonsoft JSON framework at Json.Net have produced a free framework for transmitting objects using the JSON (JavaScript Object Notation) model. Because these libraries are free, open source, and simple to use, they have become extremely popular, and we see them increasingly bundled with many Windows Store apps. Unfortunately, these libraries often take the blame for failures that occur when handling corrupted or invalid objects, even when they are not at fault. The call stack below shows one example of this failure, where an invalid sequence of characters was read while deserializing an object.

0:020> !pe
Exception object: 000000f0a1cfd838
Exception type: Newtonsoft.Json.JsonReaderException
Message: Unexpected character encountered while parsing value: <. Path '', line 0, position 0.
InnerException: <none>
StackTrace (generated):
SP IP Function
000000F0BAEECE20 00007FF82E489BC4 Newtonsoft_Json_ni!Newtonsoft.Json.JsonTextReader.ParseValue()+0xd51e4
000000F0BAEECEA0 00007FF82E3B39A0 Newtonsoft_Json_ni!Newtonsoft.Json.JsonTextReader.ReadInternal()+0x40
000000F0BAEECEF0 00007FF82E3B38AC Newtonsoft_Json_ni!Newtonsoft.Json.JsonTextReader.Read()+0x1c
000000F0BAEECF20 00007FF82E3C1F3D Newtonsoft_Json_ni!Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadForType(Newtonsoft.Json.JsonReader, Newtonsoft.Json.Serialization.JsonContract, Boolean)+0xed
000000F0BAEECF90 00007FF82E48B68F Newtonsoft_Json_ni!Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(Newtonsoft.Json.JsonReader, System.Type, Boolean)+0xcdf5f
000000F0BAEED040 00007FF82E3AF6BB Newtonsoft_Json_ni!Newtonsoft.Json.JsonSerializer.DeserializeInternal(Newtonsoft.Json.JsonReader, System.Type)+0x22b
000000F0BAEED0D0 00007FF82E3A940D Newtonsoft_Json_ni!Newtonsoft.Json.JsonConvert.DeserializeObject[[System.__Canon, mscorlib]](System.String, Newtonsoft.Json.JsonSerializerSettings)+0xbd
000000F0BAEED120 00007FF82DCF9D3C xxxxxxxx_xxxxxx_Common_ni!xxxxxxxx.xxxxxx.Common.Models.Feeds+<UpdateFeedsFromWebAsync>d__23.MoveNext()+0x32c
000000F0BAEE8550 00007FF83C691CE0 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)+0x90
000000F0BAEE8590 00007FF83C691BA4 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)+0x54
000000F0BAEE85C0 00007FF82DCF99AB xxxxxxxx_xxxxxx_Common_ni!xxxxxxxx.xxxxxx.Common.Models.Feeds+<UpdateFeedsFromWebIfNeededAsync>d__14.MoveNext()+0x1ab
000000F0BAEE5E90 00007FF83C691CE0 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)+0x90
000000F0BAEE5ED0 00007FF83C691BA4 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)+0x54
000000F0BAEE5F00 00007FF8522C681F xxxxxxxx_xxxxxx_BackgroundTask_ni!xxxxxxxx.xxxxxx.BackgroundTask.TileUpdateBackgroundTask+<Run>d__0.MoveNext()+0x16f

StackTraceString: <none>
HResult: 80131500

80131500 = COR_E_EXCEPTION “General Exception”

A review of a large number of crash dumps from the WER telemetry shows that most of the failures occur while deserializing objects, often in background tasks. This reinforces the belief that any content delivered from a remote source must be treated with suspicion, and apps should always protect themselves against invalid, unexpected, and corrupted content. Not surprisingly, the recommendation for this failure is to wrap calls that use the Newtonsoft JSON libraries with try/catch blocks, both in app code and background tasks. A decision can then be made on whether or not the app should continue, based on how crucial the objects are to app execution.

Additional resources:

HTTP request failures

The next two failures are seen while executing HTTP requests. While these are somewhat similar to the System.Net.Http.HttpClientHandler.GetResponseCallback errors discussed in the previous article (caused by name resolution failures), the underlying causes here are a bit different. Like the JSON failures, these errors are seen most frequently in background tasks.

mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd

These failures occur when the app has not implemented a task cancellation handler. The exception type and message on the outer exception, plus the information in the inner exception, shows that the web request has actually been cancelled.

The call stack below shows both exceptions, followed by the matching code from ReferenceSource that shows why the exception was thrown. Note that System.Net.HttpWebRequest.EndGetReponse is throwing the first exception when it detects that the EndCalled has already been set on the async web result. This was set earlier as part of cancelling the web request.

0:012> !pe -nested
Exception object: 01e82a34
Exception type: System.Threading.Tasks.TaskCanceledException
Message: A task was canceled.
InnerException: <none>
StackTrace (generated):
SP IP Function
0415E6D8 65EBE4E8 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)+0xa68e44
0415E6E8 6545569D mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)+0x35
0415E6F4 65EBDFDD mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(System.Threading.Tasks.Task)+0xa69455
0415E6F8 01C30B47 xxxxxxxx_Background!Unknown+0x3ef
0415E45C 65B0EACB mscorlib_ni!System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()+0x17
0415E464 65EBE4CC mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)+0xa68e28
0415E474 6545569D mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)+0x35
0415E480 01C3046C xxxxxxxx_Background!Unknown+0xb4
0415E1F0 65B0EACB mscorlib_ni!System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()+0x17
0415E1F8 65EBE4CC mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)+0xa68e28
0415E208 6545569D mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)+0x35
0415E214 01C30236 xxxxxxxx_Background!Unknown+0xae

StackTraceString: <none>
HResult: 8013153b

8013153b = >COR_E_OPERATIONCANCELED “The operation was cancelled”


Nested exception -------------------------------------------------------------
Exception object: 01e808bc
Exception type: System.Net.WebException
Message: The request was aborted: The request was canceled.
InnerException: <none>
StackTrace (generated):
SP IP Function
0415ED3C 64F62E93 System_ni!System.Net.HttpWebRequest.EndGetResponse(System.IAsyncResult)+0x6226bf
0415ED50 5A27E721 System_Net_Http_ni!System.Net.Http.HttpClientHandler.GetResponseCallback(System.IAsyncResult)+0x41

StackTraceString: <none>
HResult: 80131509

80131509 = COR_E_INVALIDOPERATION “An operation is not legal in the current state”

From http://referencesource.microsoft.com/#System/net/System/Net/HttpWebRequest.cs#10e37e4a3f52a590

 

/// <devdoc>
/// <para>Retreives the Response Result from an HTTP Result after an Async operation has completed</para>
/// </devdoc>
public override WebResponse EndGetResponse(IAsyncResult asyncResult) {
#if DEBUG
using (GlobalLog.SetThreadKind(ThreadKinds.User)) {
#endif
GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndGetResponse", ValidationHelper.HashString(asyncResult));
if(Logging.On)Logging.Enter(Logging.Web, this, "EndGetResponse", "");

//
// parameter validation
//
if (asyncResult==null) {
throw new ArgumentNullException("asyncResult");
}

LazyAsyncResult castedAsyncResult = asyncResult as LazyAsyncResult;
if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) {
throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
}
if (castedAsyncResult.EndCalled) {
throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndGetResponse"));
}
HttpWebResponse httpWebResponse = castedAsyncResult.InternalWaitForCompletion() as HttpWebResponse;
castedAsyncResult.EndCalled = true;
if (httpWebResponse == null)
{
if (Logging.On) Logging.Exception(Logging.Web, this, "EndGetResponse", castedAsyncResult.Result as Exception);
NetworkingPerfCounters.Instance.Increment(NetworkingPerfCounterName.HttpWebRequestFailed);
throw (Exception) castedAsyncResult.Result;
}
GlobalLog.Assert(httpWebResponse.ResponseStream != null, "HttpWebRequest#{0}::EndGetResponse()|httpWebResponse.ResponseStream == null", ValidationHelper.HashString(this));
// Otherwise it worked, so return the HttpWebResponse.
GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndGetResponse", ValidationHelper.HashString(httpWebResponse));
if(Logging.On)Logging.Exit(Logging.Web, this, "EndGetResponse", httpWebResponse);
InitLifetimeTracking(httpWebResponse);

FrameworkEventSource.Log.EndGetResponse(this);

return httpWebResponse;
#if DEBUG
}
#endif
}

System.Net.Http.HttpClientHandler handles the inner exception (as it is supposed to), and lets cancellation and cleanup continue for the task. This ultimately calls into the app’s task, where the second (outer) exception occurs because the app’s task is not catching the System.Threading.Tasks.TaskCanceledException exception. The outer exception fails in mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ValidateEndwhen checking to see if the task is wait-notification enabled, or if it has not been run to completion. If the app implements a handler for System.Threading.Tasks.TaskCanceledException, execution would actually never reach this code.

The recommendation here is to expect that any asynchronous activity can be cancelled at any time, and handle the appropriate cancellation exceptions that might be passed.

Additional resources:

 

System.dll!System.Net.Sockets.Socket.EndConnect

This failure is something of a catch-all for a variety of networking-related issues, so there is no specific recommendation for resolution. But the underlying causes serve as a good demonstration of the variety of environments the app might be running in, and show why defensive programming is so important.

In this case, the inner exception shows that a managed network socket call is surfacing an error returned from the lower network layers when trying to connect to a network endpoint.

0:012> !pe
Exception object: 000000915edfb3b0
Exception type: System.Net.WebException
Message: Unable to connect to the remote server
InnerException: System.Net.Sockets.SocketException, Use !PrintException 000000915edf6a70 to see more.

StackTrace (generated):
SP IP Function
0000009177A9E8D0 00007FFFCDA810E7 System_ni!System.Net.HttpWebRequest.EndGetResponse(System.IAsyncResult)+0x7e6357
0000009177A9E930 00007FFFCEAAF313 mscorlib_ni!System.Threading.Tasks.TaskFactory`1[[System.__Canon, mscorlib]].FromAsyncCoreLogic(System.IAsyncResult, System.Func`2<System.IAsyncResult,System.__Canon>, System.Action`1<System.IAsyncResult>, System.Threading.Tasks.Task`1<System.__Canon>, Boolean)+0x63
0000009177A9E280 00007FFFCE261CE0 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)+0x90
0000009177A9E2C0 00007FFFCE261BA4 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)+0x54
0000009177A9E2F0 00007FFFE000E1F4 xxxxxx_xxxxxxxxxx_ni!xxxxxx.xxxxxxxxxx.xxx.xxx+<ExecuteRequestAsync>d__0.MoveNext()+0x374
0000009177A9BC10 00007FFFCE261CE0 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)+0x90
0000009177A9BC50 00007FFFCE261BA4 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)+0x54
0000009177A9BC80 00007FFFE000DA9A xxxxxx_xxxxxxxxxx_ni!xxxxxx.xxxxxxxxxx.xxx.xxx+<LoadResponseAsync>d__0`1[[System.__Canon, mscorlib]].MoveNext()+0x1da
0000009177A995A0 00007FFFCE261CE0 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)+0x90
0000009177A995E0 00007FFFCE261BA4 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)+0x54
0000009177A99610 00007FFFE000DDB1 xxxxxx_xxxxxxxxxx_ni!xxxxxx.xxxxxxxxxx.xxx.xxx+<LoadAsync>d__9`1[[System.__Canon, mscorlib]].MoveNext()+0x171
0000009177A96E80 00007FFFCE261CE0 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)+0x90
0000009177A96EC0 00007FFFCE261BA4 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)+0x54
0000009177A96EF0 00007FFFCEACBF71 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter`1[[System.__Canon, mscorlib]].GetResult()+0x31
0000009177A96F20 00007FFFE0D38AEB xxxxxx_BackgroundTasks_ni!xxxxxx.BackgroundTasks.TileUpdater+<DoChange>d__4.MoveNext()+0x1bb
0000009177A947A0 00007FFFCE261CE0 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)+0x90
0000009177A947E0 00007FFFCE261BA4 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)+0x54
0000009177A94810 00007FFFE0D39200 xxxxxx_BackgroundTasks_ni!xxxxx.BackgroundTasks.TileUpdater+<Run>d__f.MoveNext()+0x140

StackTraceString: <none>
HResult: 80131509
There are nested exceptions on this thread. Run with -nested for details
80131509 = COR_E_INVALIDOPERATION “An operation is not legal in the current state”
0:012> !PrintException /d 000000915edf6a70

Exception object: 000000915edf6a70
Exception type: System.Net.Sockets.SocketException
Message: An attempt was made to access a socket in a way forbidden by its access permissions
InnerException: <none>

StackTrace (generated):
SP IP Function
0000009177A9EE90 00007FFFCDA5AF78 System_ni!System.Net.Sockets.Socket.EndConnect(System.IAsyncResult)+0x82e098
0000009177A9EEF0 00007FFFCD229262 System_ni!System.Net.ServicePoint.ConnectSocketInternal(Boolean, System.Net.Sockets.Socket, System.Net.Sockets.Socket, System.Net.Sockets.Socket ByRef, System.Net.IPAddress ByRef, ConnectSocketState, System.IAsyncResult, System.Exception ByRef)+0x162

StackTraceString: <none>
HResult: 80004005
80004005 = Unspecified error

While this specific example implies a conflict between socket use and access permissions, examination of a large set of dumps from the WER telemetry shows a variety of error messages being returned:

“No connection could be made because the target machine actively refused it”

“An attempt was made to access a socket in a way forbidden by its access permissions”

“A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond”

These errors can be caused by a number of things in the user’s environment, most of them beyond the developer’s control. For example:

  • Firewall settings
  • Antivirus blocking ports
  • The port is already in use
  • The port number is incorrect
  • The machine has too many open connections
  • Other issues in the user environment (restricted network access settings, router configuration, etc.)

It’s important to recognize that your app may be run in a huge variety of networking environments, and handle network connection failures gracefully. For example, a polite message stating that the network is unavailable at the moment delivers a very professional impression to the user. If sufficiently important, you may even be able to offer a list of suggestions or troubleshooting items to check.

Live Tile failures

Windows.UI.dll!Windows.UI.Notifications.TileUpdateManager.CreateTileUpdaterForApplication

Windows.UI.dll!Windows.UI.Notifications.TileUpdateManager.CreateTileUpdaterForSecondaryTile

Many apps use tile updates to convey updates and status changes. Tile updates are often implemented as background tasks that run on a scheduled basis, or when some triggering event occurs. This failure occurs when an app (or background task) attempts to update a tile using the underlying notification system. The failure indicates that the system was unable to obtain a valid application identifier.

0:006> !pe
Exception object: 023b0000
Exception type: System.Exception
Message: <Invalid Object>
InnerException: <none>
StackTrace (generated):
SP IP Function
0840EFE0 00000000 Windows_UI_ni!Windows.UI.Notifications.TileUpdateManager.CreateTileUpdaterForApplication()+0x1
0840F008 0D683A88 xxxxxxxx!UNKNOWN+0x1c
0840F018 54361154 mscorlib_ni!System.Threading.Tasks.Task.InnerInvoke()+0x4c
0840F030 54361096 mscorlib_ni!System.Threading.Tasks.Task.Execute()+0x22
04A9F8F0 543662FE mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)+0x66
04A9F900 54366290 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)+0x38
04A9F930 0AFE7954 xxxxxxxx!UNKNOWN+0x384
04A9F9D8 54738A92 mscorlib_ni!System.Runtime.CompilerServices.AsyncMethodBuilderCore.<ThrowAsync>b__4(System.Object)+0x36
04A9F9F8 63D42B7C System_Runtime_WindowsRuntime_ni!System.Threading.WinRTSynchronizationContext+Invoker.InvokeCore()+0x18

StackTraceString: <none>
HResult: 803e0102
0:006> !error 803e0102

0x803e0102 = WPN_E_INVALID_APP “The application identifier provided is invalid”

We’ve found two scenarios that cause this failure. The first is during app development when running the app in the simulator in Visual Studio. This error may be thrown when updating tiles. The recommendation is to run the app under the Local Machine setting, as seen below.

image

Secondly, this failure can occur when the underlying notification platform is not available on the user’s machine. If the notification platform has encountered an issue that caused it to terminate, it causes tile notification and updating to fail as well. The call to TileUpdateManager.CreateTileUpdaterForApplication normally retrieves the package full name, creates a notification endpoint, and performs package and app name validation for the notification subsystem. Problems with either of the last two steps can cause “The application identifier provided is invalid” to be returned, generating this exception.

Additionally, this failure can also occur when using secondary tiles and calling TileUpdateManager.CreateTileUpdaterForSecondaryTile to change the content or appearance of a secondary tile. Make sure the secondary tile is being referenced correctly with the appropriate tileID, and that the TileDisplayAttributes are set correctly. Please see the forum post, Can’t update secondary tiles, for more information.

In either case, the presence of the notification system on the customer’s machine is outside the control of the app. If notifications aren’t available, inadvertently using the notification interfaces generates an exception that should be handled by the app. It’s recommended to wrap the call to CreateTileUpdaterForApplication in a try/catch block and allow the app to keep running. For most Windows Store apps, a temporary inability to update tiles should not be a fatal condition.

Additional resources: