应该如何实施"NewUserClient"
How should "NewUserClient" be implemented
我正在尝试与应用程序中的一个dext进行交互。我可以使用IOServiceOpen
找到服务,并调用我的dext的NewUserClient
(我可以在日志中看到传递的type
参数正在输出(。在这之后,我有点不知所措。阅读这里关于NewUserClient的内容,我可以看到应该使用Create
来创建一个新的Service对象。
这里的讨论部分说propertiesKey
字典中的关键字描述了新服务
应该将此字典作为顶级条目放在系统扩展名的plist文件中,还是应该将字典与关键字一起放在IOKitPersonalities
中?
我可以将IOServiceDEXTEntitlements
密钥保留为空值,以不对连接到系统扩展的应用程序施加任何权限限制吗?
我的plist看起来是这样的(在两个位置有MyUserClientProperties
键/dict(。
<?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>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>MyUserClientProperties</key>
<dict>
<key>IOClass</key>
<string>MyUserClient</string>
<key>IOUserClass</key>
<string>MyUserUSBInterfaceDriver</string>
<key>IOServiceDEXTEntitlements</key>
<string></string>
</dict>
<key>IOKitPersonalities</key>
<dict>
<key>example_device</key>
<dict>
<key>MyUserClientProperties</key>
<dict>
<key>IOClass</key>
<string>MyUserClient</string>
<key>IOUserClass</key>
<string>MyUserUSBInterfaceDriver</string>
<key>IOServiceDEXTEntitlements</key>
<string></string>
</dict>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>IOClass</key>
<string>IOUserService</string>
<key>IOProviderClass</key>
<string>IOUSBHostInterface</string>
<key>IOUserClass</key>
<string>MyUserUSBInterfaceDriver</string>
<key>IOUserServerName</key>
<string>sc.example.MyUserUSBInterfaceDriver</string>
<key>bConfigurationValue</key>
<integer>0x1</integer>
<key>bInterfaceNumber</key>
<integer>0x0</integer>
<key>idVendor</key>
<integer>0x123</integer>
<key>idProduct</key>
<integer>0x08</integer>
</dict>
</dict>
<key>OSBundleUsageDescription</key>
<string>Example user space USB driver</string>
</dict>
</plist>
是否需要将SUPERDISPATCH
作为最后一个参数传递给Create
?
来自"OSX和iOS内核编程"第5章第81页:
I/O Kit设计的独创性在于,用户客户端对象本身就是一个驱动程序对象:IOUserClient类继承自IOService,与任何其他IOService实例一样,每个用户客户端都有一个提供程序类,对于用户客户端来说,该提供程序类是应用程序控制的驱动程序的实例
虽然以上可能只对kext(?(是正确的,但我认为事情对dext、来说是一样的
从创建文档:使用kIOUserClassKey键指定您希望系统实例化的自定义IOService子类的名称
为什么需要实例化另一个IOService
类?这门课的目的是什么?是我的类的提供程序继承自IOUserClient
吗?如果是,我如何使我的驱动程序的实例(实现NewUserClient
的实例(成为提供者?
从创建文档:使用kIOClassKey
指定要返回到服务客户端的自定义IOUserClient
子类的名称
将创建并分配给Create
的第三个参数的类的类型是什么?如果是的话,那就是我应该分配给IOUserClient*
指针的那个指针,它被传递给NewUserClient
吗?
kern_return_t IMPL(MyUserUSBInterfaceDriver, NewUserClient) {
os_log(OS_LOG_DEFAULT, "%{public}d:", type);
IOPropertyName propertiesKey = "MyUserClientProperties";
IOService* client;
auto ret = Create(this, propertiesKey, &client, SUPERDISPATCH);
// Need to do more things here...
return ret;
}
无论我尝试什么,我总是得到一个断言,但我看不出是什么导致了它
3 com.apple.DriverKit 0x0000000102f2b24b __assert_rtn + 102
4 com.apple.DriverKit 0x0000000102f2c20a IOService::Create_Impl(IOService*, char const*, IOService**) (.cold.2) + 35
5 com.apple.DriverKit 0x0000000102f1766b IOService::Create_Impl(IOService*, char const*, IOService**) + 91
6 com.apple.DriverKit 0x0000000102f2668f IOService::Create_Invoke(IORPC, OSMetaClassBase*, int (*)(OSMetaClassBase*, IOService*, char const*, IOService**)) + 135
7 com.apple.DriverKit 0x0000000102f276d7 IOService::Create(IOService*, char const*, IOService**, int (*)(OSMetaClassBase*, IORPC)) + 267
8 sc.example.MyUserUSBInterfaceDriver 0x0000000102ee0c89 MyUserUSBInterfaceDriver::NewUserClient_Impl(unsigned int, IOUserClient**) + 313 (MyUserUSBInterfaceDriver.cpp:155)
尽管DriverKit上的WWDC演示试图假装不是这样,但DriverKit对世界的看法与内核的看法非常不同,您需要了解一些实现细节,因为抽象非常泄漏。
正如您可能已经发现的那样,DriverKit驱动程序中看起来像IOService
的对象实际上是I/O注册表的内核(和用户空间(视图中的IOUserService
对象。这一差距通过DriverKit的IPC机制得以弥补。
为了创建一个新的用户客户端,您需要一个(内核(IOUserClient
子类的实例,它由您的(dext(IOUserClient
子类支持。它的内核类实际上是IOUserUserClient
。(是的,真的。(正如你所发现的,文档并不完全清楚你是如何做到这一点的。我发现查看源代码方面的可用内容很有帮助——调用NewUserClient
的内核端在这里的IOUserServer::serviceNewUserClient()
函数中实现。
您会立即注意到,如果IOServiceDEXTEntitlements
属性丢失,这不会阻止代码的成功:
prop = userUC->copyProperty(gIOServiceDEXTEntitlementsKey);
ok = checkEntitlements(entitlements, prop, NULL, NULL);
在checkEntitlements
:中
if (!prop) {
return true;
}
这是一个好消息,因为这意味着我们现在不需要担心它,可以简单地把它关掉
接下来,propertiesKey
引用了提供程序IOUserService
内核对象上的属性。您不能在dext的代码中设置这些属性,所以提供它们的唯一方法是从IOKit匹配的个性词典中。
您可以随心所欲地命名此属性,但是:
- 它的值必须是字典
- 它必须包含
"IOClass"
键值对,指定要实例化为字符串的内核类——在您的情况下是"IOUserUserClient"
- 它必须包含
"IOUserClass"
键值对。这指定了要实例化的dext类,再次作为字符串。在您的情况下,它看起来像MyUserClient
把它放在一起:
<key>IOKitPersonalities</key>
<dict>
<key>example_device</key>
<dict>
<key>MyUserClientProperties</key>
<dict>
<key>IOUserClass</key>
<string>MyUserClient</string>
<key>IOClass</key>
<string>IOUserUserClient</string>
</dict>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
…
</dict>
</dict>
…
然后,从NewUserClient
函数调用:
IOService* client = nullptr;
kern_return_t ret = this->Create(this, "MyUserClient", &client);
我认为这里不需要SUPERDISPATCH
,因为您可能没有重写类中的Create
方法,所以您的超级实现无论如何都是继承的。
然后做你的错误检查,任何其他初始化,准备等你可能需要,最后:
*userClient = client;
return kIOReturnSuccess;
- 函数何时会在c++中包含stack_Unwind_Resume调用
- Python中的for循环与C++有何不同
- 在C++中释放内存期间,迭代器与指针有何不同
- 标准对此指向成员函数类型模板参数有何说明?是我的代码有误,还是 MSVS 16.6 有问题?
- 类中的 C++ int 被设置为值,似乎不知从何而来
- -fvisibility-inline-hidden 与 gcc 中的 -fvisibility=hidden 有何不同
- 收益率和回报有何不同?
- 覆盖私有功能,它与受保护功能有何不同?
- 擦除删除成语的性能增益从何而来
- 无论代码长度如何,以下代码的内存要求有何不同?
- "virtual"对C++析构函数有何影响?
- 如果我对"while"块发表评论,为什么程序会死机?其中的"yield"线有何影响?
- 系统时间从何而来?
- stl::unordered_map 和 stl::vector 的销毁有何不同
- C++ 友元函数在内存位置上有何不同?
- 为什么我可以在不链接任何额外库的情况下包含 sys/*.h
- C 是否具有接口类概念,如果它在那里,那么它与Java接口类别有何不同
- std::u8string与std::string有何不同?
- 功能和变量从何而来
- 两种类型转换有何不同?