I've come across an issue with Core MIDI across a couple of iOS apps I work on, and another app I downloaded from the App Store.
What appears to be happening is the Core MIDI server crashes. After this happens, any interaction with Core MIDI functions or properties makes the calling app unresponsive. The following line is in AppDelegate's didFinishLaunchingWithOptions::
[MIDINetworkSession defaultSession].enabled = YES;
Execution stops at this point, causing a forever hang when debugging or a #8badf00d crash otherwise.
This happens even if the Core MIDI function should return an OSStatus - the return value never comes back:
OSStatus s = MIDIObjectGetStringProperty(ref, kMIDIPropertyDisplayName, (CFStringRef*)&string);
This call (which is in the PGMidi library) also hangs, with s not being returned. The only way to fix the issue is to restart the device.
The Core MIDI server becoming unresponsive seems related to running multiple Network Sessions from a connected Mac, but I haven't been able to pinpoint a way to replicate reliably. As well as my own apps (which use the MIKMIDI library), I have experienced unresponsive behaviour with midimittr, downloaded from the App Store.
Of course, I have no control over whether the Core MIDI Server becomes unresponsive. But is there a way to check the status of the MIDI server before making calls that may make my app unresponsive?
Update: 2019-05-10
I've found that I can get the iOS Core MIDI server into this unresponsive state by following these steps:
Set up a Network MIDI session on a Mac in Audio/MIDI Setup.
In iOS app, connect to that Network MIDI session.
Let Mac go to sleep naturally (invoking sleep from the Apple Menu doesn't appear to trigger the issue).
Once the Mac has gone to sleep do something in iOS app that will call Core MIDI.
So it's like the iOS Core MIDI server has lost connection to the Mac's MIDI network, but continues to try and execute.
Update: 2019-05-17
Apple responded to my bug report (#50657978) saying it is a duplicate of another report (#49583498) and will be closed. At the very least they are aware of the bug.
Update: 2019-07-17
This Core MIDI hang state can also be entered more quickly (for debugging purposes) by connecting the Core MIDI network via Audio Music Setup, then backgrounding your app and switching on Airplane mode on the iOS device.
SEE BELOW FOR LATEST UPDATE AND FINAL SOLUTION
I've managed to come up with a partial solution to this problem. (Alas, as the root cause seems embedded in Apple's code a complete solution is not possible.)
In my AppDelegate I now run a routine which can detect whether calls to Core MIDI will time out:
func enableMIDINetworkSession() {
let midiNetworkGroup = DispatchGroup()
midiNetworkGroup.enter()
DispatchQueue.global(qos: .background).async {
MIDINetworkSession.default().isEnabled = true
midiNetworkGroup.leave()
}
// If `midiNetworkGroup.leave()` is not reached in the closure above, then the result below will be `.timeOut`
let midiNetworkTimeoutResult = midiNetworkGroup.wait(timeout: DispatchTime.now() + 10.0)
switch midiNetworkTimeoutResult {
case .timedOut:
{ ... } // Calls to Core MIDI will cause app to hang. Handle as required. Note: app will crash anyway at some point in the future.
case .success:
break // All good, continue as before
}
}
A thing to note here: if you intend to display an alert in the case that midiNetworkTimeoutResult == .timeOut then keep in mind that any calls to Core MIDI that occur straight after this may cause the alert to not be presented (as the main queue will be blocked).
Update: 2019-07-17
It's important to mention with the solution above that if you end up in the .timedOut case above, the app will crash at some point in the future anyway, as it catches up with the MIDINetworkSession.default().isEnabled call.
The gap before the crash is around 5 minutes, so there's enough time to display an alert and advise the user to restart their device.
Update: 2019-08-14
Recommended solution
It appears that this issue has been resolved by Apple in iOS 12.4. The solution then would be to advise your users to update to iOS 12.4 or later.
(Also, this issue seems only to affect iOS 12.2 and 12.3 versions.)
Related
I am facing a very weird issue: my iPhone is restarting.
This issue occurs in a particular scenario only.
Step 1: I have a sync process in which I'm loading data for the whole app. So I'm basically doing a heavy API call by uploading 4-5 camera captured images and syncing the app data;
Step 2: After syncing, I'm pressing the iPhone home button to make the app go in background;
Step 3: I'm locking the iPhone screen(by using side button);
After a few seconds I'm seeing the apple logo and the phone seems to restart. This is not replicating when the app is connected in debug mode. I checked the debug navigator app is using only 125 MB of memory, disk and network values is 0%. Energy Impact is showing high, I'm not sure this is due to high energy impact. I'm facing this issue only on iOS 12.4.
The fact that the phone (or possibly just springboard) restarts, and not just your application means this is Apple's bug. You're not supposed to be able to crash iOS even if you try.
Finding a likely cause will be hard since the system is not behaving the way it's supposed to. The device's logs may have more information from things other than your app. This may be a system API breaking due to any number of actions from your application.
Often with this kind of thing the next OS version will fix it, but if that's not the case or it's important to track down I would try removing ways you're interaction with the system (background APIs, notifications, etc.) and see if anything fixes the issue.
If you find the problem, you may even be doing things the "correct" way according to the documentation and have to find a workaround. If you have the time you can submit a bug to Apple so the underlying issue has a better chance of being fixed.
It seems when your app is in the background and phone locked, Automatic Reference Counting (ARC) closes some connection or deallocates a resource that makes the iPhone restart. Are you closing all connections and removing all references once the upload is complete?
Phones do not spontaneously restart just because of an app’s actions. You’re having an issue with your phone, not with a program. You need to repair or replace the phone.
Starting from iOS 12 the CLLocationManager doesn't run endless anymore in the background. The app get's terminated without a crashlog at random times. This was working fine before iOS 12.
To demonstrate this problem I've created an sample app here
The demo app just launches an CLLocationManager and keep this running in the background. While running on the background we keep track of it by logging it. The problem is that the app get terminated by iOS. The demo app is created to demonstrate this problem.
Steps to reproduce
Run the app on the device
Grand access to locationmanager
Put the app to the background
Wait for 1-48hours
Result:
The app is terminated
App is terminated without any reason after random time.
Expected result:
The app is still running.
How it should work
This is confirmed by an Apple engineer:
Once the CLLocationManager updates are started in the foreground and you did all the work to have it running in the background, the location updates should run endless in the background until:
app is force quit
device is rebooted
app stops location updates
app releases the CLLocationManager object
app crashes
iOS terminates the app due to memory shortage,
the locationManager object is released, overreleased, or overwritten. You should make sure that your view controller is not being instantiated, which then resets the locationController class. If that happens when the app is in the background, you will restart updates, which will cause the app to be eventually suspended. You should make sure the locationController is a singleton.
app is crashing. Check to see if there are crash logs on the device you are testing
iOS is terminating the app due to memory shortage. In this case, you will find JetsamEvent logs on the device that shows your app being terminated. You can check the timestamps and locate the one that is around the time your app stopped working.
Updated answer:
Apple fixed this bug in iOS 12.2 beta 2 (16E5191d)
Original analyse and bug detection:
Together with Apple Developer Technical Support we have analyzed this issue with Sysdiagnose files. Following these guidelines you can install profiles to have more logging on your device. I don't know exactly how these logs work and where to find this issue, but Apple did this for me and came with this first analyse:
On the suspension event you observed on 2018/10/22 01:01:12:587, this
is what I see (about a minute after your last activity logging)
[CllocationManag:2725] Terminating with description:
{
owner = ;
target = rw.sp.flitsmeister.frameworks.CllocationManagerBackgroundTest; }
This is basically saing that your app was terminated, because the
system needed drive space, and killed a bunch of apps so it can delete
their /tmp and /Library/Caches directories. I have seen this process
to be a little more aggressive in iOS 12, but seeing you are on a
256GB device, and have ~179 GB free after the cleanup, I am finding it
hard to believe this was justified.
After sending some more sysdiagnose and reproduction cases Apple did his best to analyse and ended with the following conclusion:
Unfortunately I don’t bring good news.
It turned out that, currently in iOS 12 there is a new mechanism that
will terminate long running background apps periodically as the system
needs to free resources. At this time, this process is a bit too
aggressive, and I am working with the relevant teams to get this to
behave better.
So, at this point, I would like you to file a bug report. Explain the
symptoms. And make sure you upload the sysdiagnose files along with
the bug report. (I already sent yours in, but it doesn’t hurt to have
the new ones as well). And let me know the bug number please.
So this means that currently in iOS 12 you app won't run endless on the background. I've filled in a bug report, the number is 45581276 and will try to keep this thread updated.
I tried clearing out the /tmp and /Library/Caches directories when the app goes in the background without any change in behavior. I also tried the same periodically when the app processing background locations without any change as well.
Good day. I've been reading a lot about this problem and there are many SO questions for previous versions of iOS.
I'm wondering, for iOS 9, Can I somehow send data to the server (a request with about 20-30kbs of payload data) if the app is not opened (So it wasn't started or was force-quit)?
Or is this still a no-go as of iOS 9.3?
I can go without even receiving the response from the server (i'm that desperate)
We have been fighting with similar requirements for a long time. But we finally decided not to do it.
Apple suggests to do only a quick state log of your app so you can restore the same state when you open the app again. The best thing to do when the app is about to go to background is, to write something on disk which might be useful when the app loads again.
We tried connecting to the server every time user takes the app to background, but we saw a lot of app crash issues after adding this code. Coz, the OS force quits the app if its taking time to goto background.
We finally decided to store whatever info on the disk and then send it to server next time the app is open.
With a custom crash reporting system (like the ones specialized at Ask the user to send crash log after crash on iPhone) to send the log, the app needs to restart. Why? Isn't there a possibility to send it during the custom exception handling? Or is there a crash reporting system that doesn't need to restart the app?
When a crash occurs the app is in a highly unstable state. So a crash reporting library can not do anything since even allocating memory at crash time may cause way more damage. So crash reporting SDKs can only use so-call async-safe C methods to collect all crash data. Any Objective-C code can not be processed either and also the iOS networking stack can not be used.
Please also note that exceptions are just one example of app crashes in Objective-C, there are also crashes triggered by low-level BSD signals. Both types mean that the app is in a highly unsafe and unstable state and as little code as possible should be invoked at crash time.
So this would require a rewrite of most of the networking frameworks to be able to send data out at crash time, and this may even not be possible to do in a safe way. That is why all proper crash reporting SDKs don't do anything like that.
In addition, on iOS it is not possible to create another process which could send the data in the background, so the only safe and possible solution is to send data the next time the app starts.
Now this has another conclusion that crashes that happen early on app startup might never be sent since the app is crashing before or while it sends. Some SDKs provide mechanisms to handle that scenario which most likely requires changes in your app startup code.
Since you app crashed there is no process running any more that you app controls, thus you can not start a new process to send the report.
Any code in the crash handler only has limited time to save what ever made you app crash before iOS kill whole app and removes it from memory.
When you restart you app the crash reporter formats the crash report and sends it. This can only be down when the when you app is active.
I am integrating iCloud in my App using an UIManagedDocument. The PSC options are set when the document is initialized, and because I am debugging I always force the app to use iCloud whithout asking the user.
Everythings seems to work as expected but if on the phone or the pad I go to:
Settings -> iCloud -> Document & Data
and I turn off (if on) or on (if off) the UISwitch related to my App, it crashes without explanations.
What should I check/investigate? Am I supposed to intercept some kind of notification and do something?
Note: I am targeting iOS7 and from the documentation I understood the UIManagedDocument handling from local to ubiquity is handled automatically now, isn't it?
*Additional info: There is not exception in XCode, the app simply stops running in debug and jumps to int main(int argc, char *argv[]). On the phone/pad it keeps running, on XCode I can only restart it.
Nicola
The app is getting sent SIGKILL to force it to restart. Apparently this will happen whenever the permissions are changed. However I think this might be a new Xcode bug because my app behaves normally when not connected to Xcode and the usual checks for iCloud settings changes work fine.