IOServiceMatching无法稳定匹配dext服务的技术求助
问题描述
我们开发的iPad端App启动时执行以下代码查找dext服务(驱动已在iOS设置中提前启用):
io_service_t mService = IO_OBJECT_NULL; kern_return_t ret = kIOReturnSuccess; io_iterator_t iterator = IO_OBJECT_NULL; // 临时检查所有服务,后续会用其他Key优化 CFMutableDictionaryRef matchingDict = IOServiceMatching("IOUserService"); if (__builtin_available(iOS 15.0, *)) { ret = IOServiceGetMatchingServices(kIOMainPortDefault, matchingDict, &iterator); } else { // 早期版本兼容逻辑 } if (ret != kIOReturnSuccess) { printf("Unable to find service"); } while ((mService = IOIteratorNext(iterator)) != IO_OBJECT_NULL) { // 只有先启动App再连接设备时,才能找到"MyDriver" ret = IOServiceOpen(mService, mach_task_self_, 0, &mConnection); .......... }
使用IOServiceMatching("IOUSBDevice")结合idVendor+idProduct匹配设备时,无论设备先连还是后连都正常,但匹配驱动时存在以下问题:
- 先连接USB设备再启动App:MyDriver的
Start()未被调用,IOServiceMatching("IOUserService")无法找到MyDriver; - 先启动App再连接设备:MyDriver正常启动,可正常匹配并调用
IOServiceOpen; - 驱动运行时,在iOS设置中禁用再启用驱动(不插拔设备):MyDriver的
Start()不触发,也无法再次匹配。
驱动Info.plist中IOProviderClass本应设为IOUSBHostDevice(设备为非HID USB设备),当前驱动配置文件如下:
驱动Info.plist
<plist version="1.0"> <dict> <key>IOKitPersonalities</key> <dict> <key>MyDriver</key> <dict> <key>CFBundleIdentifier</key> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> <key>CFBundleIdentifierKernel</key> <string>com.apple.kpi.iokit</string> <key>CFBundleName</key> <string>$(PRODUCT_NAME)</string> <key>IOClass</key> <string>IOUserService</string> <key>IOMatchCategory</key> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> <key>IOProviderClass</key> <string>IOUserResources</string> <key>IOResourceMatch</key> <string>IOKit</string> <key>IOUserClass</key> <string>MyDriver</string> <key>IOUserServerName</key> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> <key>MyDriverUserClientProperties</key> <dict> <key>IOClass</key> <string>IOUserUserClient</string> <key>IOUserClass</key> <string>MyDriverClient</string> </dict> <key>bConfigurationValue</key> <integer>1</integer> <key>bInterfaceNumber</key> <integer>0</integer> <key>idProduct</key> <integer>1234</integer> <key>idVendor</key> <integer>5678</integer> </dict> </dict> </dict> </plist>
驱动entitlements文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>com.apple.developer.driverkit</key> <true/> <key>com.apple.developer.driverkit.transport.usb</key> <array> <dict/> </array> <key>com.apple.security.app-sandbox</key> <true/> </dict> </plist>
解决方案
针对问题1和3,核心是修正驱动匹配逻辑,让驱动能正确关联已连接的USB设备,同时让App能监听驱动服务的动态变化:
1. 修正驱动Info.plist的匹配配置
当前Info.plist中IOProviderClass设为IOUserResources是错误的,需改为IOUSBHostDevice,同时调整匹配规则:
- 将
IOProviderClass的值从IOUserResources改为IOUSBHostDevice - 删除
IOResourceMatch键值对(该配置针对资源服务,不适用于USB设备) - 确保
idVendor、idProduct、bConfigurationValue、bInterfaceNumber等USB匹配参数与目标设备一致
修改后的MyDriver Personality核心片段:
<key>IOProviderClass</key> <string>IOUSBHostDevice</string> <key>IOMatchCategory</key> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> <key>IOUserClass</key> <string>MyDriver</string> <key>IOUserServerName</key> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> <key>bConfigurationValue</key> <integer>1</integer> <key>bInterfaceNumber</key> <integer>0</integer> <key>idProduct</key> <integer>1234</integer> <key>idVendor</key> <integer>5678</integer>
2. 优化App端的服务查找逻辑
不要直接匹配所有IOUserService,改用驱动的IOMatchCategory进行精准匹配:
CFMutableDictionaryRef matchingDict = IOServiceMatching("IOUserService"); CFDictionarySetValue(matchingDict, CFSTR("IOMatchCategory"), CFSTR("$(PRODUCT_BUNDLE_IDENTIFIER)")); if (__builtin_available(iOS 15.0, *)) { kern_return_t ret = IOServiceGetMatchingServices(kIOMainPortDefault, matchingDict, &iterator); if (ret != kIOReturnSuccess) { printf("Unable to find service"); } while ((mService = IOIteratorNext(iterator)) != IO_OBJECT_NULL) { ret = IOServiceOpen(mService, mach_task_self_, 0, &mConnection); // 处理连接逻辑 IOObjectRelease(mService); } IOObjectRelease(iterator); } else { // 早期版本兼容逻辑 }
3. 监听驱动服务的动态变化
针对驱动禁用再启用的场景,使用IOServiceAddMatchingNotification注册监听,实时捕获驱动服务的出现事件:
void driverAppearedCallback(void *refcon, io_iterator_t iterator) { io_service_t service; while ((service = IOIteratorNext(iterator)) != IO_OBJECT_NULL) { // 处理新出现的驱动服务 kern_return_t ret = IOServiceOpen(service, mach_task_self_, 0, &mConnection); // 后续业务逻辑 IOObjectRelease(service); } } // App启动时注册监听 CFMutableDictionaryRef matchDict = IOServiceMatching("IOUserService"); CFDictionarySetValue(matchDict, CFSTR("IOMatchCategory"), CFSTR("$(PRODUCT_BUNDLE_IDENTIFIER)")); io_iterator_t iterator; kern_return_t ret = IOServiceAddMatchingNotification( kIOMainPortDefault, kIOFirstMatchNotification, matchDict, driverAppearedCallback, NULL, // 可传递App上下文 &iterator ); // 触发初始查找 driverAppearedCallback(NULL, iterator);
上述配置完成后,无论设备先连接还是后连接,驱动都能正确匹配启动;驱动重新启用时,App也能通过监听事件捕获到驱动服务并建立连接。
内容的提问来源于stack exchange,提问作者K880
相关产品推荐
相关产品推荐

