Soru İOS çökme muhabirleri, MonoTouch uygulamalarını kilitlemekten nasıl korunur?


İOS'ta iOS dahil olmak üzere çok sayıda iOS kilitlenme raporlama kütüphanesi var. Test uçuşu ve HockeyApp. Hizmetlere bağlı kalmak istemiyorsanız, yine de PLCrashReporter. Bu kütüphaneleri bağlamak oldukça önemsiz çünkü onların genel API'sı genellikle birkaç başlatma yöntemiyle birkaç sınıftan oluşur.

Ancak, bizim uygulamada TestFlight ve daha sonra HockeyApp kullanmaya çalışırken, bizim app rastgele çökmeye başladı. Çıkıyor, bu olduğu bilinen bir sorun rapor  birkaç  zamanlarama Xamarin bu konuda uyarmıyor, nispeten belirsiz ve zor yoldan bulduk.

Bunu öğrendik tüm iOS kilitlenme raporları Mono'nun boş referans istisnalarını yakalamasını önler:

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

Bu neden oluyor? Bir Xamarin geliştiricisi olan Rolf'u alıntılamak,

Boş bir referans istisnası aslında ilk başta bir SIGSEGV sinyalidir. Genellikle   mono çalışma zamanı bunu işler ve nullreference istisnasına çevirir,   yürütmenin devam etmesine izin vermek. Sorun şu ki SIGSEGV sinyalleri bir   ObjC uygulamalarında çok kötü bir şey (ve yönetilen kodun dışında gerçekleştiğinde)   herhangi bir kilitlenme raporlama çözümü bir kaza olarak rapor edecektir (ve uygulamayı öldür) -   Bu MonoTouch SIGSEGV işlemek için bir şans elde etmeden önce olur, yani   MonoTouch bu konuda hiçbir şey yapamaz.

Eminim MonoTouch uygulamalarında birçok TestFlight'ı, çökmelere neden olduğunu bilmeden kullanırım.
Bu ironik değil mi? 

Kilitlenme raporlama kütüphanelerini nasıl yapıyorsunuz? değil kazasında MonoTouch uygulamaları?


50
2018-01-24 10:40


Menşei


Merak eden biri varsa, bunlar bizim MonoTouch için HockeyApp bağlamaları. HockeyApp özgür değil ama onların desteği gerçekten çok iyi (TestFlight hakkında söyleyemediğim bir şey) ve genellikle onlardan memnun kaldık. Bu düzeltmeyi örnek projeye ekledim. (Feragatname: Biz herhangi bir şekilde bağlı değiliz.) - Dan Abramov
Burada Crittercism'in kurucu ortağı - aslında Mono ile iyi çalışan Xamarin için resmi olarak desteklenen bir eklenti yayınladık - örneğin Mono'nun SIGSEGV sinyallerini yakalamasını engellemiyor. Mono'nun çalışma zamanını bunları halledelim ve sonra bunları Crittercism'e gönderelim. Buradan indirebilirsiniz: components.xamarin.com/view/crittercism - crittercismrob


Cevaplar:


Bunu içine koy 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 ();
}

Aramak EnableCrashReporting () başında FinishedLaunching yöntem.
Bu aramayı sarın #if !DEBUG eğer istersen.


O nasıl çalışır?

Rolf'un önerisini takip ettim:

Tek bir çözüm, tüm SIGSEGV sinyallerinin ele alınabilmesi için mono'ya izin verilmesidir.   (teknik olarak konuşurken kilitlenme raporlaması lib'unun ya ele almaması gerekir.   SIGSEGV sinyali, ya da mono işleyicisine zincirleme yapmalı ve   kendi başına herhangi bir işlem). Mono, SIGSEGV sinyalinin olduğunu belirlerse   yönetilen koddan değil (yani çok kötü bir şey oldu), olacak   SIGABORT sinyalini yükseltmek   işlemek ve çökmek gibi davranmak). Anlayabileceğiniz gibi bu bir şey   Bu, kilitlenme raporlama kitaplığında yapılmalıdır.

Ve Landon FullerHedef C uygulaması:

#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;
}

kullandım Banshee kaynak kodu nasıl çağrılacağına dair bir referans noktası olarak sigaction MonoTouch'dan.

Umarım yardımcı olur!


58
2018-01-24 10:40



@Nic Landon ve Rolf'un önerilerini takip ettim, kredi onlara ulaştı! - Dan Abramov
Bu harika! Daha önce testflight kullanıyordum ama bu sebepten dolayı çıkardım. Tekrardan vahşi çökme raporlarını almak için sabırsızlanıyorum. - Dermot
Bunun için çok teşekkür ederim, keşke daha çok bilinen olsaydı, bana bir sürü güçlük çıkarırdı - MarkDaniel
Xamarin.Insights ile denedim ama işe yaramıyor, hala uygulama çökmeleri alıyorum. - Peyman
@Peyman Bir süredir bu yüzden cevabın hala doğru olduğunu garanti edemem. Bugzilla'da bir sorun bildirmelisiniz. - Dan Abramov


Xamarin.iOS 10.4 ile başlayarak şu anda bunu yapmak için desteklenen bir yol var:

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 ();
}

3
2018-02-23 16:21