realm / realm-swift

Realm is a mobile database: a replacement for Core Data & SQLite
https://realm.io
Apache License 2.0
16.32k stars 2.15k forks source link

iOS 14 + Xcode 12 (Beta 3, Beta 4, Beta 5 & Beta 6): When Realm is stored in a shared app group container, backgrounding the app triggers: Message from debugger: Terminated due to signal 9 #6671

Closed kunalsood closed 3 years ago

kunalsood commented 4 years ago

Goals

Have my app continue to run normally, when backgrounded, with Realm stored in a shared app group container.

Expected Results

Same as "Goals" [above].

Actual Results

When, I run the app on an actual device, and swipe up while my app is in the foreground to send it to the background, the app quits with the following message in Xcode:-

Message from debugger: Terminated due to signal 9

Additionally: This only happens if I'm holding a reference to a live RLMResults or a notification token (those are the two things I have tested this with so far).

Interestingly, when I run the project with the default realm configurations (i.e. Realm is stored in the documents directory), this issue disappears.

It might be worth mentioning: It appears that the crash report produced on device for this issue when debugger isn't attached shows: Termination Reason: Namespace RUNNINGBOARD, Code 0xdead10cc, which would indicate that the application is being terminated by the OS because it held on to a file-lock/database-lock during suspension. (Could be un-related, though there is nothing other than Realm in my project that would hold on to a file-lock/database-lock ever).

Steps for others to Reproduce

Build and run the sample project using Xcode 12 (Beta 3, Beta 4, Beta 5, or Beta 6) on an actual device running iOS 14 (Beta 3, Beta 4, Beta 5, or Beta 6). (I have tested this on an iPhone & an iPad)

Code Sample

Here is a (quick & dirty) sample project: https://github.com/kunalsood/KSRealmTerminationSample

Most of the relevant code in the project is in: ViewController.m file & one realm model object file KSSampleObject.h.

Version of Realm and Tooling

Realm framework version: 5.3.2 (pre-built dynamic framework) UPDATE: Sample project has now been updated to include Realm using SPM.

Realm Object Server version: N/A

Xcode version: 12.0 (Beta 3, Beta 4, Beta 5 & Beta 6)

iOS/OSX version: iOS 14 (Beta 3, Beta 4, Beta 5 & Beta 6)

Dependency manager + version: N/A

gongzhang commented 3 years ago

I'm sad to report that on iOS 15.0 beta 1, I'm once again getting the 0xdead10cc crash when the app opens a new Realm in the background and performs a write operation.

SquaredTiki commented 3 years ago

For what it's worth, I haven't yet been able to reproduce this on iOS 15 beta 1.

gongzhang commented 3 years ago

For what it's worth, I haven't yet been able to reproduce this on iOS 15 beta 1.

It's not 100% reproduced. And I cannot reproduce it on my own devices no matter in dev or release mode.

But I indeed received a lot of crash reports from users who are using iOS 15. ☚ī¸

tgoyne commented 3 years ago

Could it be related to SDK version? I assume any users hitting it would be using versions built against iOS 14 SDKs while the obvious way to test locally would involve building against the iOS 15 SDK. Would be pretty weird if they started enforcing no file locks but only for existing apps, though...

gongzhang commented 3 years ago

The article below discussed a similar issue about sharing a SQLite database in app group. The widget extension will be killed by the system watchdog from time to time, due to 0xdead10cc (hold a file lock after process suspension). Since WidgetKit has no APIs related to process lifecycle management, there is no simple way to work around the problem as long as file locks are used.

https://inessential.com/2020/02/13/how_we_fixed_the_dreaded_0xdead10cc_cras

From my collected analysis data, it is clear that iOS 15 has improved the detection strength for 0xdead10cc. I'm not quite sure how I should address this issue at this point.

schmidan commented 3 years ago

We are seeing this as well (sdk 14 build, iOS 15 beta3).

Does anyone know of a workaround or do we have to move realm out of the shared group container?
Or does the Realm Team work on a fix?

(we are on 10.7.7 atm because of https://github.com/realm/realm-cocoa/issues/7344)

gongzhang commented 3 years ago

🙋‍♂ī¸ Update:

I finally fixed the 0xdead10cc crash. And I must admit that the check for file locks in iOS and watchOS are correct, while the detection in the recent 15.0 betas seems to be more comprehensive. It is also possible that the background execution time has been shortened. Anyway, this exposes potential issues in my app.

It's totally ok to store the database in a shared container. The real problem is that the file lock is not released indeed at the moment the process suspends. In other words, the realm.write { ... } transaction does not complete when current process is going to be suspended.

I made the following changes to completely fix the 0xdead10cc crash, which you can refer to.

1. Keep write transactions as short as possible. Avoid putting irrelevant code in a transaction.

  // before:
  realm.write {
    heavyTaskWithDataModifications()
  }

  // after:
  let diff = heavyTaskThatGenerateDataDiff()
  realm.write {
    diff.apply() // much shorter transaction
  }

2. Avoid performing irrelevant tasks when the app is wake up in background.

Modern iOS has many reasons to wake up your app in the background and then hang it again quickly, such as handling remote notifications, responding to WatchConnectivity, background HealthKit updates, background refresh tasks, etc. You need to examine each of these situations carefully. In particular, my code is based on the concept of reactive programming, so it's easy to accidentally execute unnecessary code in the background.

3. No secret sauce

I didn't use ProcessInfo.beginActivity(...).

schmidan commented 3 years ago

For what it is worth: The problem "went away". We are still on 10.7.7 but building with XCode 12.5.1 stops the app from crashing on iOS 15 devices.

sync-by-unito[bot] commented 3 years ago

➤ Jason Flax commented:

We're going to close this out because the original user's issue was fixed. However, we are going to open up a new issue to document how Realm works with App Groups and in Background Fetch.

gongzhang commented 2 years ago

Update: My previous fixes stopped working since iOS 15.4.

🙋‍♂ī¸ Update:

I finally fixed the 0xdead10cc crash. And I must admit that the check for file locks in iOS and watchOS are correct, while the detection in the recent 15.0 betas seems to be more comprehensive. It is also possible that the background execution time has been shortened. Anyway, this exposes potential issues in my app.

It's totally ok to store the database in a shared container. The real problem is that the file lock is not released indeed at the moment the process suspends. In other words, the realm.write { ... } transaction does not complete when current process is going to be suspended.

I made the following changes to completely fix the 0xdead10cc crash, which you can refer to.

1. Keep write transactions as short as possible. Avoid putting irrelevant code in a transaction.

// before:
realm.write {
  heavyTaskWithDataModifications()
}

// after:
let diff = heavyTaskThatGenerateDataDiff()
realm.write {
  diff.apply() // much shorter transaction
}

2. Avoid performing irrelevant tasks when the app is wake up in background.

Modern iOS has many reasons to wake up your app in the background and then hang it again quickly, such as handling remote notifications, responding to WatchConnectivity, background HealthKit updates, background refresh tasks, etc. You need to examine each of these situations carefully. In particular, my code is based on the concept of reactive programming, so it's easy to accidentally execute unnecessary code in the background.

3. No secret sauce

I didn't use ProcessInfo.beginActivity(...).

IAmMichellis commented 2 years ago

In case anyone comes across this again: I had a relevant related issue with mysterious SIGKILLS, idle main threads, and suspicious background threads accessing a RLMRealm in a shared group container. Info / solution here https://github.com/realm/realm-swift/issues/7466#issuecomment-1149948784