50 votes

Comment empêcher les rapporteurs de crash iOS de faire planter les applications MonoTouch ?

Il existe de nombreuses bibliothèques de rapports d'accident dans iOS, notamment TestFlight y HockeyApp . Si vous ne voulez pas dépendre des services, vous pouvez toujours utiliser des bibliothèques telles que PLCrashReporter . Lier ces bibliothèques est assez trivial car leur API publique consiste généralement en quelques classes avec plusieurs méthodes d'initialisation.

Cependant, lorsque nous avons essayé d'utiliser TestFlight, et plus tard HockeyApp dans notre application, notre application a commencé à se planter de manière aléatoire. Il s'avère que, ce est un problème connu signalé plusieurs temps Mais Xamarin ne le signale pas, il est relativement obscur et nous l'avons découvert à nos dépens.

Nous avons appris que tous les rapports de crash d'iOS empêchent Mono d'attraper les exceptions de référence nulle :

try {
    object o = null;
    o.GetHashCode ();
} catch {
    // Catch block isn't called with crash reporting enabled.
    // Instead, the app will crash.
}

Pourquoi cela se produit-il ? Citation de Rolf, un développeur Xamarin,

Une exception de référence nulle est en fait un signal SIGSEGV au départ. Habituellement, le runtime mono gère cela et le traduit en une exception de référence nulle, permettant à l'exécution de continuer. Le problème est que les signaux SIGSEGV sont une très mauvaise chose dans les applications ObjC (une exception de référence nulle est une exception de référence nulle). très mauvaise chose dans les applications ObjC (et lorsqu'ils se produisent en dehors du code géré), donc toute solution de reporting de crash le signalera comme un crash (et tuera l'application). cela se produit avant que MonoTouch ait la possibilité de gérer le SIGSEGV, donc il n'y a MonoTouch ne peut rien y faire.

Je suis sûr que beaucoup utilisent TestFlight dans les applications MonoTouch sans savoir qu'il provoque des plantages.
N'est-ce pas ironique ?

Comment faire des bibliothèques de rapports d'accidents no des applications MonoTouch en panne ?

1 votes

Si quelqu'un est curieux, ce sont nos Liaisons HockeyApp pour MonoTouch . HockeyApp n'est pas gratuit mais leur support est vraiment bon (ce qui est quelque chose que je ne peux pas dire de TestFlight) et généralement nous avons été satisfaits d'eux. J'ai ajouté ce correctif à l'exemple de projet. (Disclaimer : Nous ne sommes pas affiliés de quelque manière que ce soit).

1 votes

Cofondateur de Crittercism, nous avons publié ici un plugin pour Xamarin officiellement supporté qui fonctionne bien avec Mono. Par exemple, il n'empêche pas Mono de capter les signaux SIGSEGV. Nous laissons le runtime Mono les gérer et les envoyons ensuite à Crittercism. Vous pouvez le télécharger ici : composants.xamarin.com/view/crittercism

57voto

Dan Points 16670

Mettez ça dans AppDelegate.cs :

[DllImport ("libc")]
private static extern int sigaction (Signal sig, IntPtr act, IntPtr oact);

enum Signal {
    SIGBUS = 10,
    SIGSEGV = 11
}

static void EnableCrashReporting ()
{
    IntPtr sigbus = Marshal.AllocHGlobal (512);
    IntPtr sigsegv = Marshal.AllocHGlobal (512);

    // Store Mono SIGSEGV and SIGBUS handlers
    sigaction (Signal.SIGBUS, IntPtr.Zero, sigbus);
    sigaction (Signal.SIGSEGV, IntPtr.Zero, sigsegv);

    // Enable crash reporting libraries
    EnableCrashReportingUnsafe ();

    // Restore Mono SIGSEGV and SIGBUS handlers            
    sigaction (Signal.SIGBUS, sigbus, IntPtr.Zero);
    sigaction (Signal.SIGSEGV, sigsegv, IntPtr.Zero);

    Marshal.FreeHGlobal (sigbus);
    Marshal.FreeHGlobal (sigsegv);
}

static void EnableCrashReportingUnsafe ()
{
    // Run your crash reporting library initialization code here--
    // this example uses HockeyApp but it should work well
    // with TestFlight or other libraries.

    // Verify in documentation that your library of choice
    // installs its sigaction hooks before leaving this method.

    var manager = BITHockeyManager.SharedHockeyManager;
    manager.Configure (HockeyAppId, null);
    manager.StartManager ();
}

Appelez EnableCrashReporting () au début de FinishedLaunching méthode.
Enveloppez cet appel dans #if !DEBUG si vous le souhaitez.


Comment cela fonctionne-t-il ?

J'ai suivi la suggestion de Rolf :

Une solution possible est de permettre à mono de gérer tous les signaux SIGSEGV (techniquement parlant, la librairie de rapport de crash ne devrait soit pas gérer le signal SIGSEGV, ou bien elle doit être reliée au gestionnaire de mono et ne faire traitement par elle-même). Si mono détermine que le signal SIGSEGV ne provient pas du code géré (c'est à dire que quelque chose de très mauvais s'est produit), il va signal SIGABORT (que la librairie de rapport de crash devrait déjà gérer et déjà gérer et traiter comme un crash). Comme vous pouvez le comprendre, c'est quelque chose qui doit être fait dans la bibliothèque de rapports de collision.

Et Landon Fuller L'implémentation de l'Objective C de la Commission européenne :

#import <signal.h>

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    /* Save Mono's signal handler actions */
    struct sigaction sigbus_action, sigsegv_action;
    sigaction(SIGBUS, NULL, &sigbus_action);
    sigaction(SIGSEGV, NULL, &sigsegv_action);

    // Enable the crash reporter here. Ie, [[PLCrashReporter sharedReporter] enableCrashReporterAndReturnError:],
    // or whatever is the correct initialization mechanism for the crash reporting service you're using

    /* Restore Mono's signal handlers */
    sigaction(SIGBUS, &sigbus_action, NULL);
    sigaction(SIGSEGV, &sigsegv_action, NULL);

    return YES;
}

J'ai utilisé Code source de Banshee comme point de référence pour savoir comment appeler sigaction de MonoTouch.

J'espère que cela vous aidera !

0 votes

@Nic J'ai juste suivi les suggestions de Landon et de Rolf, donc le mérite leur revient !

0 votes

C'est génial ! J'utilisais testflight avant mais je l'ai supprimé pour cette raison. J'ai hâte de pouvoir à nouveau obtenir des rapports de crashs en temps réel.

0 votes

Merci beaucoup pour cette information, j'aurais aimé qu'elle soit plus connue, cela m'aurait évité bien des tracas.

4voto

Rolf Bjarne Kvinge Points 12829

À partir de la version 10.4 de Xamarin.iOS, il existe désormais un moyen de le faire :

static void EnableCrashReporting ()
{
    try {
    } finally {
        Mono.Runtime.RemoveSignalHandlers ();
        try {
            EnableCrashReportingUnsafe ();
        } finally {
            Mono.Runtime.InstallSignalHandlers ();
        }
    }
}

static void EnableCrashReportingUnsafe ()
{
    // Run your crash reporting library initialization code here--
    // this example uses HockeyApp but it should work well
    // with TestFlight or other libraries.

    // Verify in documentation that your library of choice
    // installs its sigaction hooks before leaving this method.

    // Have in mind that at this point Mono will not handle
    // any NullReferenceExceptions, if there are any 
    // NullReferenceExceptions on any thread (not just the current one),
    // then the app will crash.

    var manager = BITHockeyManager.SharedHockeyManager;
    manager.Configure (HockeyAppId, null);
    manager.StartManager ();
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X