Why is restart needed to send crash log on iOS? - ios

With a custom crash reporting system (like the ones specialized at Ask the user to send crash log after crash on iPhone) to send the log, the app needs to restart. Why? Isn't there a possibility to send it during the custom exception handling? Or is there a crash reporting system that doesn't need to restart the app?

When a crash occurs the app is in a highly unstable state. So a crash reporting library can not do anything since even allocating memory at crash time may cause way more damage. So crash reporting SDKs can only use so-call async-safe C methods to collect all crash data. Any Objective-C code can not be processed either and also the iOS networking stack can not be used.
Please also note that exceptions are just one example of app crashes in Objective-C, there are also crashes triggered by low-level BSD signals. Both types mean that the app is in a highly unsafe and unstable state and as little code as possible should be invoked at crash time.
So this would require a rewrite of most of the networking frameworks to be able to send data out at crash time, and this may even not be possible to do in a safe way. That is why all proper crash reporting SDKs don't do anything like that.
In addition, on iOS it is not possible to create another process which could send the data in the background, so the only safe and possible solution is to send data the next time the app starts.
Now this has another conclusion that crashes that happen early on app startup might never be sent since the app is crashing before or while it sends. Some SDKs provide mechanisms to handle that scenario which most likely requires changes in your app startup code.

Since you app crashed there is no process running any more that you app controls, thus you can not start a new process to send the report.
Any code in the crash handler only has limited time to save what ever made you app crash before iOS kill whole app and removes it from memory.
When you restart you app the crash reporter formats the crash report and sends it. This can only be down when the when you app is active.

Related

How to get error reports of a freezing iOS app?

Recently I had an issue in my iOS app that caused the app to freeze. The UI was unresponsive and the user had to kill and restart the app to make it work again.
In Google's Play Console I see such issues as ANRs ('Application not responding' errors).
But in Xcode I don't get any reports unfortunately. Crashlytics also didn't show any reports.
Is it possible to somehow get some kind of report with a stacktrace similar to the ANRs in Google's Play Console?
Please note:
I know what caused the app to freeze in this specific issue and also how to debug and fix it. What I
want is an error report in case the issue wasn't found during QA but it is
occurring in a user session.
The freezing version was not published to App Store, only to
TestFlight.
The reason for unresponsive UIs could be due to a number of reasons:
One reason could be because of high load (running out of RAM, Swap Space). For detecting these scenarios (without crashing behavior) you need Application Performance Monitoring, for example with Firebase. The advantage with Firebase is you don't have to prompt for consent, so you get more data to detect hangs. The Xcode Organizer can provide Hang Rate metrics though if you have enough users who have consented to share their data (new in Xcode 11).
Another reason could be due to logical errors in code. For example, a user triggers an unexpected app flow that was missed during manual testing. In these instances, it can be harder to narrow down but could be trackable with manual user testing beforehand e.g TestFlight. You can use In-App Feedback tools (users send you emails) to gather context about the issue or Instabug for screenshots and advanced feedback.
The other reason could be because of deadlocks. If you use DispatchGroup for instance or DispatchSemaphores to queue network requests and the requests time out then that could also lead to suspended UI frames. I would look carefully at where you leave the dispatch group as well - all possible branches should have a dispatch_group_leave statement to avoid hanging on dispatch_group_wait.
You can use the Thread State Trace Instrument to see whether system calls are blocking your main thread to debug this issue. The classic iOS dev advice is to only perform UI updates on the main thread and move all other logic to a background thread. This may not solve the root cause but does prevent hangs. The same logic applies for Core Data fetches, inserts, deletes, and updates. Move Core Data operations to background threads in network request callbacks as well.
If you get crash reports, it's simple to diagnose an OOM error in a Crashlytics crash report for example (comes up in Insights). Heap corruption can also be inferred from crash reports, and while the metadata may not be the same for the same behavior, it could point you to a screen or action when you try and reproduce the bug.
Watchdog Unresponsive App crashes can be intercepted to come up in crash reports if the user doesn't kill the app beforehand, but you mentioned the user killed the app so this may not be available.
There is no direct equivalent ANR error reporting for iOS apps, given that Hang Rates are only aggregated if enough sessions have been detected. You could do screen recording of app sessions (ServiceNow), but I don't advise it because it has privacy implications.
Crashlytics is unable to send abnormal terminations fired by the watchdog. I've researched this for Jetsam terminations. You will see them in the console logs. see this link for the watchdog crash iOS generates: Watchdog Unresponsive App. If there's a way to monitor the main thread for queued operations executing for too long, you could fire a fatal error ie fire a fatal before the watchdog terminates the app.
Do some research on MetricKit. It's new to iOS 13. There's a class called MXHangDiagnostic. You can use it in your app to monitor for hangs and report on them as you see fit.

iOS Framework and Crash reporting

I'm developing an iOS framework and I like to be able to log data for posible crashes. I don't like to use external logging framework like Fabric to avoid conflicts with the main app that uses the framework. Which should be the best approach to do that. Can I use the dsym files in any way? Thanks a lot.
If I correctly understand what you're trying to achieve; you'd like to get crash reports from apps which link against your framework however only if they occurred directly as a result of the code provided by the framework?
This would be fairly difficult to achieve, as crashes occur at the process level rather than your framework having its own isolated 'section' or subprocess.
You could potentially catch some Objective-C exceptions by writing code to detect and prevent them from resulting in crashes, however major faults such as EXC_BAD_ACCESS would not be 'detectable' without processing the app's crash logs.
If you decide to analyse the crash logs themselves (e.g. when the app next launches), this would require the dSYM of the specific application and build to symbolicate the crash. Once you've symbolicated the crash, you'd then need some logic to determine if the crash was likely due to your framework or not. If you receive crash reports from multiple apps, you'd need to ensure that you use the correct dSYM for each log, as this will very likely be different for each one.

Crashlytics for iOS does logs crash only when app is opened after the crash

In an iOS Mobile App why does crashlytics log crash and send email, when the iOS app is opened after the crash. This behavior is not consistent when crashlytics is integrated with android app.
Typically after a crash, user will stop using the app and not open it again. As a consequence we end up missing several crashes which happen in iOS.
Mike from Fabric here. The behavior is different on each platform since each platform has different behaviors for exception handling and networking.
On iOS, it's unsafe to send much, if any, data after an exception happens that leads to a crash. The app is a horrible state and the device is also resolving an unexpected situation. If, we or other services, tried to send additional data then, you could run the risk of causing an issue on the entire device which it would require the device to restart. Asking a user to restart their device is a much worse behavior then having them need to relaunch the app.
You are correct that some users may never relaunch the app and those crashes are lost, but in general, we've found most users relaunch the app post-crash.
As #Dev_Tandel said, on Android, other background networking services can be used to try and send the crash report then. We will try to do that, but don't guarantee that a report will be sent until the app is relaunched.

How crash reporting tools really work

I know there are many crash reporting tools available in the market to collect crashes from the real devices. I would like to know how a crash reporting tool really collects its data?. Does it collect a crash report from the operating system once the crashed application launched again? or Does iOS allows the crash reporter to collect the data as soon as the app is crashed?.
It will be really great if somebody can explain what happens after an app is crashed or point me to right place.
System crash logs are located at /private/var/mobile/Library/Logs/CrashReporter/ and (as far as I know) can't be accessed by the app directly. Most crash reporting tools will try to catch crashes and generate their own crash reports which will get stored locally and sent to a server for symbolication and processing.
You can take a look at the source for KSCrash, an open source crash reporting tool, to see how crashes are caught/stored/reported.

Generating crash reports on Cocoa Touch apps

That probably sounds a lot worse than it is, but here's my question.
I am dealing with a crash on an actual device, that one of my tester's is using. At the moment, there is no way to discover what is causing the crash. I can not reproduce it on the simulator. However, on the simulator when something crashes I get log info about it in the output window. But I don't want to keep testing with the device connected.
Is it possible to log crash exceptions, etc into a file when things crash. I know certain apps can do it, but I am not sure how?
Any info would be appreciated.
There are generally two ways to do that:
Someone get the tester to send you the crash reports, that iOS created on the device. This is usually too tricky for end users, so the next suggestion works better. That's also why I am not describing how to do that :) But you'll find plenty of documentations on that process.
Integrate a crash reporting library, that catches the crashes and allows you to receive them in various ways. You should not implement your own global crash exception handler, things are just too complex to do it right (even though other people will tell you otherwise). Also crashes caused by exceptions are only one type of crashes.
There are multiple open source libraries out there, the safest one to use is anything based on PLCrashReporter. Most others use private or undocumented iOS APIs, or are not async-safe, which basically means those can destroy app data or make the crash even worse. See this blog post about the topic: http://landonf.bikemonkey.org/code/crashreporting/Reliable_Crash_Reporting_1.1.20130119.html
The following linked answer shows some of the available options on how to add logging to your app and also various options on how to receive crash reports for test version and also once the app is released: Including custom data into iOS crash dumps
If you're open to using a third party service, I use https://www.crashlytics.com. Makes debugging crashes from user devices painless.

Resources