We have app and notification extension both loading an agent lib to access the same files with read/write/delete operations. To avoid app and notification extension access the file simultaneously, we use boost::interprocess::file_lock when app enters foreground and notification extension didReceive notifications. If extension failed to grab file lock, it will skip loading agent and returns. If app failed to grab file lock, it will start a timer to keep trying while UI will display spinner. Sometimes we saw crash report from our app with:
Exception Type: EXC_CRASH (SIGKILL) Exception Codes: 0x0000000000000000, 0x0000000000000000 Termination Reason: RUNNINGBOARD 3735883980 Triggered by Thread: 0
The code 3735883980 indicate "deadlock" - The operating system terminated the app because it held on to a file lock or SQLite database lock during suspension.
In sysdiagnose, we also see "[osservice<com.apple.InputUI>:1496] check if suspended process is holding locks" in runningboardd process. Does it mean that our app fail to unlock?
We did lock when app enters foreground and unlock when app goes to background. Is there anything we did wrong?
@implementation FileLock
-(id)init
{
self = [super init];
if (nil != self)
{
// Find empty lock file, created if it doesn't exist.
FILE *file = fopen(lockFile.c_str(), "a");
if (file)
{
fclose(file);
}
m_lock = boost::make_shared<boost::interprocess::file_lock>(lockFile.c_str());
}
return self;
}
-(BOOL)lock
{
return m_lock->try_lock();
}
-(void)unlock
{
return m_lock->unlock();
}
@end
func applicationDidBecomeActive(_ application: UIApplication)
{
if !bFileLockAcquired
{
if fileLock.lock()
{
bFileLockAcquired = true
// load agent
}
else
{
lockTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: { _ in
DispatchQueue.main.async {
if fileLock.lock()
{
self.lockTimer?.invalidate()
self.lockTimer = nil
bFileLockAcquired = true
// load agent
}
}
})
}
}
func applicationDidEnterBackground(_ application: UIApplication)
{
self.lockTimer?.invalidate()
self.lockTimer = nil
fileLock.unlock()
bFileLockAcquired = false
}