0

I'm having big troubles using FSEventStream in my XPC service (code below). Service starts, stream is created, but callback function is never called. When I copy exactly the same code to my main application and run it, it works just fine. What may be the reason that it doesn't work in XPC service? I've tried to disable AppSandbox in both parts, but it didn't change anything. Any help with this is highly appreciated.

code:

- (void)initEventNotificationStreamForPath:(NSString *)path {

NPDLOG(@"Starting up FS event listener for path: %@", path);

NSArray *pathsToWatch = @[path];

FSEventStreamContext context;
context.info = (__bridge void *)self;
context.version = 0;
context.retain = NULL;
context.release = NULL;
context.copyDescription = NULL;

NSTimeInterval latency = 1.0;

_eventStream = FSEventStreamCreate(NULL, &eventNotificationCallback, &context, (__bridge CFArrayRef)pathsToWatch, kFSEventStreamEventIdSinceNow,      //[lastEventID unsignedLongLongValue],
        (CFAbsoluteTime)latency, (kFSEventStreamCreateFlagUseCFTypes | kFSEventStreamCreateFlagFileEvents | kFSEventStreamCreateFlagWatchRoot));

if(_eventStream) {

    NPDLOG(@"Scheduling event stream on runloop");

    FSEventStreamScheduleWithRunLoop(_eventStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);

    if(!FSEventStreamStart(_eventStream)) {
        NPDLOG(@"Could NOT start event stream listener!!!");
    }
    else {

        CFStringRef description = FSEventStreamCopyDescription(_eventStream);

        NPDLOG(@"Stream description: %@", description);

        CFRelease(description);
    }
}
else {
    NPDLOG(@"Could NOT create event stream listener!!!");
}
}

My callback function:

void eventNotificationCallback(ConstFSEventStreamRef streamRef, void *userData, size_t numEvents, void *eventPaths, const FSEventStreamEventFlags eventFlags[], const FSEventStreamEventId eventIds[]) {


//[((__bridge NPScannerServiceAgent *)userData).remoteObject didUpdateFilesAtPaths:(__bridge NSArray *)eventPaths];

printf("CALLBACK CALLED!!!\n");

NSLog(@"GOT FS CHANGE NOTIFICATION FROM %@", (__bridge NPScannerServiceAgent *)userData);

size_t i;

for(i = 0; i < numEvents; i++) {

    NSLog(@"Modified path: %@, flags: %d", [(__bridge NSArray *)eventPaths objectAtIndex: i], eventFlags[i]);
}
}
Matthes
  • 515
  • 5
  • 12

1 Answers1

2

By default, an XPC service does not have a run loop. Try using FSEventStreamSetDispatchQueue() instead of FSEventStreamScheduleWithRunLoop() to have the callback function triggered on a GCD queue instead of a specific run loop.

  • Thanks for this tip, it's really interesting point I didn't know about. Will try as soon as I get back to it. Btw. how it comes that XPC's do not have a run loop? I thought that when -resume method is called, it creates it's own run loop as it never returns. – Matthes Feb 19 '15 at 18:38
  • Another SO question talking about adding a run loop: http://stackoverflow.com/questions/27806541/using-sockets-with-nsxpcconnection. The gist is this: in your XPC's info.plist set `RunLoopType` to `NSRunLoop` See Apple's docs for XPC Service Property List Keys: https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingXPCServices.html – AJ Venturella Jul 16 '16 at 15:14