Swift Privileged Helper(XPC Listener)崩溃,非法指令错误

时间:2017-09-07 12:15:32

标签: swift macos xpc nsxpcconnection

我创建了一个Swift macOS应用程序,它使用SMJobBless创建一个具有升级权限的帮助程序。这很好 - 帮助程序安装到/Library/Privileged Helper Tools,并在/Library/LaunchDaemons中创建随附的LaunchDaemon。但是,帮助程序无法成功启动。相反,它会以“非法指令:4”消息崩溃。

我已经准备好帮助程序,通过实现NSXPCListenerDelegate协议来响应XML连接。这是我的助手main.swift代码:

import Foundation

class HelperDelegate: NSObject, NSXPCListenerDelegate {    
    func listener(_ listener: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool {        
    newConnection.exportedInterface = NSXPCInterface(with: HelperToolProtocol.self)
        newConnection.exportedObject = HelperTool()
        newConnection.resume()
        return true
    }    
}

let delegate = HelperDelegate()
let listener = NSXPCListener.service()
listener.delegate = delegate
listener.resume()

崩溃发生在最后一行listener.resume()

我尝试从命令行手动启动帮助应用程序(这与LaunchDaemon的操作相同),并且再次崩溃时,上面的错误消息打印到stdout。我对如何根本原因进行测试没有任何想法。在Apple’s guidlines for implementing XM services之后,我的实施不仅仅是基本的。此外,SO上关于XML服务的各种帖子并没有帮助我解决这个问题。有没有人试图成功在Swift中创建特权助手?顺便说一句,该应用程序不是沙盒。

为了完整起见,以下是我HelperTool课程中引用的HelperDelegate类的代码:

import Foundation

class HelperTool: NSObject, HelperToolProtocol {
    func getVersion(withReply reply: (NSData?) -> ()) {
        let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString" as String) as? String ?? "<unknown version>"
        let build = Bundle.main.object(forInfoDictionaryKey: kCFBundleVersionKey as String) as? String ?? "<unknown build>"
        if let d = "v\(version) (\(build))".data(using: .utf8, allowLossyConversion: false) {
            reply(d as NSData)
        }
    }
}

最后是HelperToolProtocol

import Foundation

@objc(HelperToolProtocol) protocol HelperToolProtocol {
    func getVersion(withReply: (NSData?) -> ())
}

感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

经过几天的测试后,我终于找到了一个解决方案,它使我的XPC助手正确启动并响应任何消息。问题在于当前读取的main.swift模块的最后三行

let listener = NSXPCListener.service()
listener.delegate = delegate
listener.resume()

,正如问题所示,使助手在最后一行立即崩溃。

我直接从Apple’s Creating XPC Services documentation获取了这些行。以下是NSXPCListener resume()函数的文档:

  

如果在service()对象上调用,则此方法永远不会返回。因此,在设置任何所需的初始状态并配置监听器本身之后,应将其称为XPC服务主函数内的最后一步。

解决方法是不调用NSXPCListener.service()单例对象,而是使用NSXPCListener初始化程序实例化一个新的init(machServiceName:)对象,传递相同的Mach服务名称正在主应用程序的XPC连接上使用。因为resume()在这种情况下会立即恢复 - 从而终止帮助程序 - 你必须将它放在当前的运行循环上,让它不确定地运行。这是新的工作代码:

let listener = NSXPCListener(machServiceName: "Privilege-Escalation-Sample.Helper")
listener.delegate = delegate
listener.resume()
RunLoop.current.run()