前面 已经讲解了基于 KernControl API 的通信实现,该实现相对简单,但有一些缺点。内核向应用层传输消息需调用ctl_enqueuedata接口,该接口实际将数据缓存至缓冲区,当需要瞬时大量传输消息时,缓冲区容量有限,将丢弃后来的数据。如果传输的数据有优先级,则需对ctl_enqueuedata接口进行二次封装,避免高优先级数据丢失。
classDriverClient : public IOUserClient { OSDeclareDefaultStructors(DriverClient);
public: // Called as part of IOServiceOpen in clients. boolinitWithTask(task_t owningTask, void *securityID, UInt32 type)override;
// Called after initWithTask as part of IOServiceOpen. boolstart(IOService *provider)override;
// Called when this class is stopping. voidstop(IOService *provider)override;
// Called when a client manually disconnects (via IOServiceClose). IOReturn clientClose(void)override;
// Called when a client dies. IOReturn clientDied(void)override;
// Called during termination. booldidTerminate(IOService *provider, IOOptionBits options, bool *defer)override;
// Called in clients with IOConnectSetNotificationPort. 用于数据传输 IOReturn registerNotificationPort(mach_port_t port, UInt32 type, UInt32 refCon)override;
// Called in clients with IOConnectMapMemory. 用于数据传输 IOReturn clientMemoryForType(UInt32 type, IOOptionBits *options, IOMemoryDescriptor **memory)override;
// Called in clients with IOConnectCallScalarMethod. 设置对外通信调用接口 IOReturn externalMethod(UInt32 selector, IOExternalMethodArguments *arguments, IOExternalMethodDispatch *dispatch, OSObject *target, void *reference)override;
// 建立与内核驱动的连接 var result =IOServiceOpen(nextService, mach_task_self_, 0, &connection) if result != kIOReturnSuccess { Logger(.Error, "Failed to open kext service [\(String.init(format: "0x%x", result))].") IOObjectRelease(nextService) break }
// 调用驱动方法测试连接 result =IOConnectCallScalarMethod(connection, kNuwaUserClientOpen.rawValue, nil, 0, nil, nil) if result != kIOReturnSuccess { Logger(.Error, "An error occurred while opening the connection [\(result)].") IOObjectRelease(nextService) break }
funcwaitForDriver(matchingDict: CFDictionary) { var iterator: io_iterator_t =0 let selfPointer =Unmanaged.passUnretained(self).toOpaque() let notificationQueue =DispatchQueue(label: "your queue name")
let appearedCallback: IOServiceMatchingCallback= { refcon, iterator in let selfPtr =Unmanaged<YourClassName>.fromOpaque(refcon!).takeUnretainedValue() selfPtr.processConnectionRequest(iterator: iterator) }
funcstopProvider() -> Bool { let result =IOServiceClose(connection) if result !=KERN_SUCCESS { Logger(.Error, "Failed to close IOService [\(String.init(format: "0x%x", result))].") returnfalse }