NSXPCConnection fails to transport IOSurfaceRef

I'm trying to send an IOSurfaceRef across an NSXPCConnection on osx 10.13 and I'm having trouble with the solution that was provided in the forum thread "Efficiently sending data from an XPC process to the host application." https://developer.apple.com/forums/thread/126716 From that thread:

However, that specific problem got resolved on 10.12 where we introduced a new Objective-C

Code Block
IOSurface
object, and that object is transportable directly over
Code Block
NSXPCConnection
. So double yay!
But it doesn’t seem to work. I have a very simple service protocol that includes
Code Block
- (void)sendFrame:(IOSurfaceRef)frame;
along with some basic NSString sending methods that successfully transfer across my NSXPCConnection. I have a valid (non-NULL) IOSurface in my app that I send to my helper app with sendFrame, and when the call is executed in the helper, the resulting frame is always NULL.

On the other hand, I’ve also tried creating an IOSurface with the (deprecated) kIOSurfaceIsGlobal property and sending the IOSurface’s ID instead with:
Code Block
- (void)sendFrameID:(uint32_t)frameID;
and
Code Block
[_service sendFrameID:IOSurfaceGetID(surface)];
And on the helper app side, I look up the IO to get an IOSurfaceRef:
Code Block
IOSurfaceRef frame = IOSurfaceLookup(frameID);
and it works correctly – I get a valid IOSurface which I can display and see the same pixel contents in both the app and the helper.

So what is meant by the new IOSurface object in 10.12 is “transportable directly” over NSXPCConnection? How is it supposed to work? I’m specifically interested in no-copy transfer. Thanks!

Replies

Some additional info: when I try the same code on a 10.15 mac, sendFrame results in an uncaught exception "encodeDataAt:ofObjCType: unencodable type (^{__IOSurface=})". sendFrameID still works.

  • a year late, but you're trying to send an IOSurfaceRef, you need to send an IOSurface (see IOSurface/IOSurfaceObjC.h)

Add a Comment

I'm trying to send an IOSurfaceRef across an NSXPCConnection

I don’t have any obvious answers for you, alas. I recommend that you open a DTS tech support incident so that I, or one of my colleagues, can dig into this in more detail.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"

Rather than sending an IOSurfaceRef, send an IOSurface *:

- (void)sendFrame:(IOSurface *)frame;

IOSurfaceRef is toll-free bridged to IOSurface *, so all you need to do is cast to IOSurface * and it should work.

This is true of other CF-types. Objective-C types (NSString, NSDictionary, etc.) work via NSXPCConnection but their corresponding CF-types (CFStringRef, CFDictionaryRef, etc.) don't.

The IOSurface framework contains functions to create xpc_object_t objects for xpc usage.

xpc_object_t IOSurfaceCreateXPCObject(IOSurfaceRef aSurface);
IOSurfaceRef IOSurfaceLookupFromXPCObject(xpc_object_t xobj);

https://developer.apple.com/documentation/iosurface/1419429-iosurfacecreatexpcobject?language=objc

https://developer.apple.com/documentation/iosurface/1419449-iosurfacelookupfromxpcobject?language=objc