Intermittent Xamarin.iOS crash with no exception thrown

TimCoulterTimCoulter USMember ✭✭

I have created a Xamarin.Forms app with Android and iOS projects. The Android build appears to run fine, but the iOS build occasionally crashes and I am struggling to pin down the cause, as no crash log is produced and no exception is reported in the application output.

The app accepts input from a Bluetooth-connected barcode scanner and (after some validation) displays it and writes it to a local SQLite database, accessed using SQLite.NET. A worker process also periodically synchronizes the local database with a central database via a REST API call.

Under heavy load (non-stop barcode scanning) the app crashes after typically 200 or 300 barcodes have been scanned. The crash appears to occur when a barcode scan coincides with a REST API call (although I have not been able to conclusively prove this). I don't believe this is a thread safety issue, as I have implemented the SQLite recommended pattern of accessing the database via dedicated SQLiteConnection instances for each thread (but I am happy to be corrected if I have got this wrong).

I am puzzled how such a crash can occur, leaving absolutely no evidence of its cause. Is there somewhere else I should be looking for the evidence, apart from within Xcode's Devices window? Shouldn't I expect an exception to be reported in the application output, while debugging?

I have implemented logging handlers for AppDomain.CurrentDomain.UnhandledException and TaskScheduler.UnobservedTaskException but they don't appear to be called. Is there some other way I can instrument my code to trap the cause of this crash?

Many thanks for your advice,
Tim

Answers

  • ChristianSvrdChristianSvrd SEMember ✭✭✭

    The same issue here

  • JoeProJoePro CAUniversity ✭✭✭
    edited July 2017

    Based on your description of the issue, this could likely be an out of memory crash.
    Your best bet would be to profile the app in order to spot cycles and break them.

    OOM crashes, and some native exceptions, aren't caught by mono. iOS crash logs can be helpful in such cases, but my understanding is OOM crashes don't generate a crash log.

  • TimCoulterTimCoulter USMember ✭✭

    Thanks for your replies Christian and Joe.

    There was indeed a memory leak problem (present on iOS but not Android) which I tracked down to three separate causes (including Xamarin.Forms itself, specifically the navigation stack, which leaks horribly in certain circumstances).

    After fixing (or implementing workarounds for) all 3 memory leak problems, the intermittent crash issue was still present. With no diagnostic information available, it was very difficult to pinpoint the actual cause of the crash, but it appears to be a threading problem related to SQLite (on iOS only).

    Through many hours of trial and error, I believe I have implemented at a SQLite pattern that is stable on IOS (although it is difficult to be 100% certain with an issue that is so intermittent). It essentially entails 3 elements:

    1. configuring the underlying SQLite instance in serialized mode
    2. opening a single SQLite connection and sharing it between services that need database access
    3. implementing explicit thread locking around database write operations
  • ChristianSvrdChristianSvrd SEMember ✭✭✭
    edited October 2018

    @TimCoulter How did you manage to set sqlite instance to run in serialized mode? the Xamarin Documentation is archaic suggests methods that never existed like SqliteConnection.SetConfig(SQLiteConfig.Serialized); dunno what they were smoking when they wrote that.

  • TimCoulterTimCoulter USMember ✭✭

    @ChristianSvrd Here are a few snippets from my current codebase (which has been working without crashes since I posted the above question).

    The database serialization is configured when you create an instance of a sqlite-net ISQLitePlatform implementation, so it needs to be done separately in each platform project.

    // Android Implementation
    public static ISQLitePlatform GetDatabasePlatform()
    {
        var platform = new SQLitePlatformAndroidN();
    
        platform.SQLiteApi.Shutdown();
        platform.SQLiteApi.Config(ConfigOption.Serialized);
        platform.SQLiteApi.Initialize();
    
        return platform;
    }
    
    // iOS Implementation
    public static ISQLitePlatform GetDatabasePlatform()
    {
        var platform = new SQLitePlatformIOS();
    
        platform.SQLiteApi.Shutdown();
        platform.SQLiteApi.Config(ConfigOption.Serialized);
        platform.SQLiteApi.Initialize();
    
        return platform;
    }
    
    // Usage in shared code
    var connection = new SQLiteConnection(GetDatabasePlatform(), _databasePath, SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create | SQLiteOpenFlags.FullMutex, true);
    

    Hope this helps :)

  • ChristianSvrdChristianSvrd SEMember ✭✭✭

    @TimCoulter thanks for the answer :)
    btw what nuget package you are using for sqlite? I'm using sqlite-net-pcl nuget package and cannot find ISQLitePlatform interface in it.

  • TimCoulterTimCoulter USMember ✭✭

    @ChristianSvrd Sorry if I confused you by suggesting that I am using sqlite-net. It's actually SQLite.Net, and the Nuget packages are as follows:

    SQLite.Net.Core-PCL
    SQLite.Net-PCL
    SQLite.Net.Platform.XamarinAndroidN

    There doesn't appear to be a platform-specific package for iOS.

  • TimCoulterTimCoulter USMember ✭✭

    BTW, on my later Xamarin projects I have migrated away from SQLite.Net and started using Entity Framework Core SQLite. The migration is a little painful but the flexibility gain makes it worthwhile.

Sign In or Register to comment.