"NewUserClient"应如何设置?被实施 [英] How should "NewUserClient" be implemented
问题描述
我正在尝试与应用程序中的dext交互.我可以使用 IOServiceOpen
找到该服务,并且可以调用我的dext的 NewUserClient
(我可以看到正在输出的 type
参数在日志中).在此之后,我有点迷路了.在这里阅读有关 NewUserClient 的信息,我可以看到应该使用 Create
来创建一个新的Service对象.
讨论"部分此处说 propertiesKey
词典中的键描述了新服务.
应该将此字典作为顶级条目放置在系统扩展的plist文件中,还是应该使用 IOKitPersonalities
中的键放置该字典?
我是否可以将 IOServiceDEXTEntitlements
键保留为空值,以便不对连接到系统扩展的应用程序上的权利施加任何限制?
我的plist看起来像这样(在两个地方都有 MyUserClientProperties
键/字典).
<?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><整数> 0x1</整数>< key> bInterfaceNumber</key><整数> 0x0</整数>< key> idVendor</key><整数> 0x123</整数>< key> idProduct</key>< integer> 0x08</integer></dict></dict>< key> OSBundleUsageDescription</key>< string>示例用户空间USB驱动程序</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:",类型);IOPropertyName propertiesKey ="MyUserClientProperties";IOService *客户端;自动ret =创建(this,propertiesKey,& client,SUPERDISPATCH);//需要在这里做更多的事情...返回ret}
无论我尝试什么,我总会得到一个断言,但是我看不出是什么导致了它.
3 com.apple.DriverKit 0x0000000102f2b24b __assert_rtn + 1024 com.apple.DriverKit 0x0000000102f2c20a IOService :: Create_Impl(IOService *,char const *,IOService **)(.cold.2)+ 355 com.apple.DriverKit 0x0000000102f1766b IOService :: Create_Impl(IOService *,char const *,IOService **)+ 916 com.apple.DriverKit 0x0000000102f2668f IOService :: Create_Invoke(IORPC,OSMetaClassBase *,int(*)(OSMetaClassBase *,IOService *,char const *,IOService **))+ 1357 com.apple.DriverKit 0x0000000102f276d7 IOService :: Create(IOService *,char const *,IOService **,int(*)(OSMetaClassBase *,IORPC))+ 2678 sc.example.MyUserUSBInterfaceDriver 0x0000000102ee0c89 MyUserUSBInterfaceDriver :: NewUserClient_Impl(unsigned int,IOUserClient **)+ 313(MyUserUSBInterfaceDriver.cpp:155)
正如在DriverKit上的WWDC演示试图假装成其他方式一样,DriverKit的世界观与内核的观相差很大,您需要了解一些实现细节,因为抽象是非常泄漏的.
您可能已经发现,DriverKit驱动程序中的 IOService
对象实际上是内核(和用户空间)视图中的 IOUserService
对象.I/O注册表.差距是通过DriverKit的IPC机制来弥补的.
要创建新的用户客户端,您需要一个(内核) 放在一起: 然后,从您的 我不认为这里需要 然后进行错误检查,其他可能需要的初始化,准备工作等,最后: I am trying to interact with a dext from an application. I am able to find the service using The Discussion part here says The keys in the Should this dictionary be placed in the plist file for the system extension as a top level entry, or should the dictionary be placed with the key in Can I leave the My plist looks like this (with the Do I need to pass From "OSX and iOS kernel programming" chapter 5 page 81: The ingenuity of the I/O Kit design is that user client objects are themselves a driver object: the IOUserClient class inherits from IOService and, as with any other IOService instance, each user client has a provider class that, for a user client, is the instance of the driver that the application is controlling. While the above might only be correct for kext (?) I would assume that things work in the same way for a dext, From Create documentation: Use the kIOUserClassKey key to specify the name of the custom IOService subclass that you want the system to instantiate. Why is another From Create documentation: Use the Is the type of the class that will be created and assigned to the third argument of No matter what I try I always get an assert, but I cannot see what is causing it.
As much as the WWDC presentation on DriverKit tried to pretend otherwise, DriverKit's view of the world is very different from the kernel's and you need to be aware of some implementation details, because the abstraction is extremely leaky. As you've probably already discovered, what looks like an For creating a new user client, you want an instance of a (kernel) One thing you'll notice straight away is that if the and in This is great news as it means we don't need to worry about it for the minute, and can simply leave it off. Next, it turns out that the You can name this property however you want, but: Putting it together: Then, from your I don't believe Then do your error checking, any other initialisation, preparation, etc. you might need, and finally:
这篇关于"NewUserClient"应如何设置?被实施的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋! IOUserClient
子类的实例,该子类由您的(下一个) IOUserClient
子类支持.内核类实际上是 IOUserUserClient
.(是的,是真的.)正如您所发现的,文档尚不清楚您如何进行此操作.我发现查看源代码方面的功能很有帮助-调用 NewUserClient
的内核方面键-值对,并指定要实例化为字符串的 kernel 类-在您的情况下为"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 *客户端= nullptr;kern_return_t ret = this-> Create(this,"MyUserClient",& client);
SUPERDISPATCH
,因为您大概不会覆盖类中的 Create
方法,因此无论如何您都将继承超实现.
* userClient =客户端;return kIOReturnSuccess;
IOServiceOpen
and I get a call to NewUserClient
of my dext (I can see the type
parameter passed being output in the log). After this I am a bit lost. Reading here about NewUserClient I can see that one should use Create
to create a new Service object.propertiesKey
dictionary describe the new service.IOKitPersonalities
?IOServiceDEXTEntitlements
key with an empty value to not impose any restrictions about entitlements on the application that is connecting to the system extension?MyUserClientProperties
key / dict in two places).<?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
as the last argument to Create
?IOService
class needed to be instantiated? What is the purpose of this class? Is it the provider for my class that inherits from IOUserClient
? If so how can I make the instance of my driver (the one that implements NewUserClient
) the provider?kIOClassKey
to specify the name of the custom IOUserClient
subclass to return to clients of your service.Create
? If so, is that the one I should assign IOUserClient*
pointer to, which is passed to 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)
IOService
object in your DriverKit driver is actually an IOUserService
object in the kernel's (and user space's) view of the I/O registry. The gap is bridged via DriverKit's IPC mechanism.IOUserClient
subclass, which is backed by your (dext) IOUserClient
subclass. The kernel class for this is actually IOUserUserClient
. (Yes, really.) As you've found, the documentation isn't exactly clear on how you go about this. I found it helpful to take a look at what's available in terms of source code - the kernel side of invoking NewUserClient
is implemented in the IOUserServer::serviceNewUserClient()
function here.IOServiceDEXTEntitlements
property is missing, this won't prevent the code from succeeding: prop = userUC->copyProperty(gIOServiceDEXTEntitlementsKey);
ok = checkEntitlements(entitlements, prop, NULL, NULL);
checkEntitlements
: if (!prop) {
return true;
}
propertiesKey
refers to a property on the provider IOUserService
kernel object. You can't set those properties from inside the dext's code, so the only way to provide them is from the IOKit matching personality dictionary.
"IOClass"
key-value pair, specifying the kernel class to instantiate as a string - in your case, "IOUserUserClient"
"IOUserClass"
key-value pair. This specifies the dext class to instantiate, again as a string. In your case, that looks like 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
function, call: IOService* client = nullptr;
kern_return_t ret = this->Create(this, "MyUserClient", &client);
SUPERDISPATCH
is needed here, as you presumably don't override the Create
method in your class, so you super-implementation is inherited anyway. *userClient = client;
return kIOReturnSuccess;