appcenter-sdk-apple icon indicating copy to clipboard operation
appcenter-sdk-apple copied to clipboard

Equivalent method for setting BitCrashManagerCallbacks

Open hypherion2 opened this issue 4 years ago • 11 comments

Description

Using HockeyApp SDK for Mac, we had the option to set a callback method for doing additional (simple) tasks when the crash occurs, prior to program termination:

  • (void)setCrashCallbacks: (BITCrashManagerCallbacks *) callbacks;

There's no similar option in the AppCenter SDK, will this be made available? Our app clears log files on app restart so it's too late to retrieve them by the time the MSCrashesDelegate starts.

Details

  1. Which SDK version are you using?
    • 2.2.0
  2. Which OS version did you experience the issue on?
    • OS X 10.14
  3. Which Cocoapods version are you using (run pod --version)?
    • manual
  4. What device version did you see this error on? Were you using an emulator or a physical device?
    • Mac Mini
  5. What language are you using?
    • [X ] Objective C
    • [ ] Swift

hypherion2 avatar Aug 06 '19 17:08 hypherion2

Hey @hypherion2 - can you elaborate on your use case a bit more? What kind of tasks are you trying to accomplish? Thanks!

winnie avatar Aug 08 '19 22:08 winnie

As I mentioned, we use it to save/backup the logs so we can include them in the crash report. They are automatically overwritten on next app restart, before we get notified that the app had previously crashed, so we can no longer include them with AppCenter crash reporting.

hypherion2 avatar Aug 09 '19 07:08 hypherion2

@winnieli1208 we also dump UIView & UIViewController hierarchy and general application state before process terminates. It is very useful for investigations of hard to reproduce cases.

damirdavletov avatar Aug 20 '19 16:08 damirdavletov

Thanks for the additional context. It looks like a relatively small feature for our team to implement and I've added this to our roadmap. I don't have an exact target date at this moment but I will post here when I have a clearer timeline.

Thanks!

winnie avatar Aug 20 '19 18:08 winnie

Another use-case: I'm using AVAudioRecorder to record audio and the audio file becomes corrupt if the app crashes. However, if I would be able to call recorder.stop() in a "setCrashCallbacks"-type callback, the recording would not be corrupt.

sindresorhus avatar Aug 27 '20 11:08 sindresorhus

@sindresorhus you cannot safely call any Objective-C methods in the signal handler. Please read more about it (restrictions) in underlying library (that was used in HockeyApp too) docs: https://github.com/microsoft/plcrashreporter/blob/6b7ca9a2faad6ea990ff60b0a3ee4fdf3db59150/Source/CrashReporter.h#L205-L231

MatkovIvan avatar Aug 27 '20 11:08 MatkovIvan

@MatkovIvan I'm ok with that. The recording is already corrupt without, so it cannot become worse.

sindresorhus avatar Aug 27 '20 12:08 sindresorhus

As I understand, using AppCenterCrashes means using NSSetUncaughtExceptionHandler is not possible since AppCenter sets up systems to catch all possible crashes. I also understand that there is no exposed callback/delegate-method that we could use to do a cleanup operation before the crashed app terminates, because the sources of the crash can be diverse, and the app can be in an unpredictable state.

However I would like to know if there is a way to still mitigate some of the crash scenarios. Are there hooks from AppCenter, or from AppKit, that can be called to try to run a last-minute cleanup after a crash? Again, I understand a catch-all method is not possible, but what can be done to try and catch some of these cases? I mentioned NSSetUncaughtExceptionHandler above. Maybe there is a way to still set this callback up, and get some scenarios covered there?

Thanks a lot!

Note: my app is in Swift 5.

lwouis avatar Feb 26 '21 11:02 lwouis

Hi @lwouis

Thank you for reaching out to us! You are right, there is no exposed callback or delegate calling when the crash is happened. And yes, It is not safe to execute a clean up code in a signal handler, as Ivan mentioned above.

However, if you are still interested in using the NSSetUncaughtExceptionHandler in your app, what you can try do is to chain the handlers. First, start the AppCenter Crashes, then retrieve the handler set by AppCenter using NSGetUncaughtExceptionHandler, save it locally, write your handler and call app center’s saved handler at the end of your handler. Then set your handler using NSSetUncaughtExceptionHandler. This way you will handle the error in your app and then allow app center to handle it and send the crash the AppCenter portal. You can also try reverse the handler calls order. However if you do so, there is no guarantee that the app center handler will be executed correctly since it will depend on the code in your handler, so you can expect to potentially miss some crashes.

Please keep in mind that using NSSetUncaughtExceptionHandler does not guarantee to handle all crashes, and its usage can lead to an unpredictable results.

DmitriyKirakosyan avatar Mar 02 '21 19:03 DmitriyKirakosyan

Thanks @DmitriyKirakosyan for the pointers!

That strategy you described focuses on NSSetUncaughtExceptionHandler, which to my understanding only catches objc exceptions. My question about a hook/callback from AppCenter Crashes was in hopes that I could cover more scenarios that one of my objc dependencies throwing.

Is there a way I could hijack something here in my objc class which extends NSApplication?

@import Cocoa;
@import AppCenterCrashes;
#import "AppCenterApplication.h"

@implementation AppCenterApplication

- (void)reportException:(NSException*)exception {
  [MSCrashes applicationDidReportException:exception];
  [super reportException:exception];
}

- (void)sendEvent:(NSEvent*)theEvent {
  @try {
    [super sendEvent:theEvent];
  } @catch (NSException* exception) {
    [self reportException:exception];
  }
}

@end

I want to run literally one function call before exiting. It's an OS API called CGSSetSymbolicHotKeyEnabled. I expect it to be extremely short. Best case scenario, it gets called and users doesn't have any issue. Worst case scenario it doesn't get called, and we are back to the current situation. In that sense I feel hooking an attempt somewhere within AppCenter Crashes machinery would be a net benefit.

lwouis avatar Mar 08 '21 15:03 lwouis

There's no public APIs for it. That is an existing feature request, but up until mid-2021 we mainly focus on reliability and improving performance : Roadmap

Jamminroot avatar Mar 10 '21 11:03 Jamminroot

Internally some of this code already exists. Microsoft are using the post crash callback from PLCR for their own purposes (applying an interface shim) and have put in half of the code necessary to expose a second level callback to the user, in MSACCrashesPrivate.h

I exposed it for my own purposes at https://github.com/jbb1003/appcenter-sdk-apple/tree/feature/post_crash_callback - I keep a RAM log and dump it to store (with signal-safe code) in the event of a crash so I can add it as an attachment to a crash.

Obviously a crash could trample over the memory used for the log, or for storing the file path of the log, but in general it won't, and this approach has proved very useful in the past (when I was using HockeyApp).

UPDATE

I had a further look at how MS are using the PLCR post crash callback, and realised that MS are doing pretty much what I wanted to achieve (and the code has the same potential issues regarding memory trampling). If you log an Analytics event, and it has not been uploaded prior to a crash, it will be saved to file during the crash and then uploaded with the crash report. So there is no loss of data. This gets me enough of what I want that it's no longer worth me forking the SDK, but I will leave the code up there in case it's useful for anyone else.

jbb1003 avatar Aug 24 '23 11:08 jbb1003

As we do not have plans to add support for this feature in the next year, I'm closing the issue.

DmitriyKirakosyan avatar Sep 22 '23 06:09 DmitriyKirakosyan