swiftmacosxpciosurface

How to properly send IOSurface to another process using XPC?


I'm developing a MacOS application in which I'm trying to send a IOSurface from an XPC Service to a client application (in the same project as the XPC service), but there is something I'm clearly missing. I get the following error:

Exception: Attempt to decode an xpc type but whitelist does not specify an XPC type '<no key>'.

The whole error text follows:

2021-03-10 12:00:42.014421+0100 My Project[82813:1358040] [xpc.exceptions] 
  <NSXPCConnection: 0x600001aae6c0> connection on anonymousListener or serviceListener from pid 82827: 
  Exception caught during decoding of received selector publishNewFrame:, dropping incoming message.
Exception: Exception while decoding argument 0 (#2 of invocation):
Exception: Attempt to decode an xpc type but whitelist does not specify an XPC type '<no key>'.

I'm using the following code to send the surface:

guard let connection = processConnection else {
    print("Process is not available")
    return
}

let process = connection.remoteObjectProxyWithErrorHandler {
    error in print("remote proxy error: ", error)
} as! MyProtocol
    
let XPCSurfaceRef = IOSurfaceCreateXPCObject(unsafeBitCast(surface, to: IOSurfaceRef.self))
process.publishNewFrame(XPCSurfaceRef)

The Protocol:

@objc public protocol MyProtocol: NSObjectProtocol {
  func publishNewFrame(_ XPCSurfaceRef: xpc_object_t)
}

And on the client process:

func publishNewFrame(_ XPCSurfaceRef: xpc_object_t) {
    let surfaceRef = IOSurfaceLookupFromXPCObject(XPCSurfaceRef)
}

I have no idea of how to proceeed. I'm not clear on what exactly do I need to whitelist, or how to do it. In principle, IOSurface is a supported type in XPC, so I understand it should just work.


Solution

  • When You init Your Connection You have to whitelist the incoming classes.

    for example:

    let classSet: Set<AnyHashable> = [NSArray.self, NSDictionary.self]
    connection.remoteObjectInterface?.setClasses( classSet, for: #selector(XpcServiceProtocol.article(pzn:withReply:)), argumentIndex: 0, ofReply: true)
    

    Sometime it is a little tricky to find the Correct Classes, because Swift am Objective-C classes are sometimes not the same. You can of course use Your Custom Class