"NewUserClient"应如何设置?被实施 [英] How should "NewUserClient" be implemented

查看:104
本文介绍了"NewUserClient"应如何设置?被实施的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试与应用程序中的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机制来弥补的.

要创建新的用户客户端,您需要一个(内核) 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; 

    I am trying to interact with a dext from an application. I am able to find the service using 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.

    The Discussion part here says The keys in the propertiesKey dictionary describe the new service.

    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 IOKitPersonalities?

    Can I leave the IOServiceDEXTEntitlements key with an empty value to not impose any restrictions about entitlements on the application that is connecting to the system extension?

    My plist looks like this (with the 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>  
    

    Do I need to pass SUPERDISPATCH as the last argument to Create?

    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 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?

    From Create documentation: Use the kIOClassKey to specify the name of the custom IOUserClient subclass to return to clients of your service.

    Is the type of the class that will be created and assigned to the third argument of 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;  
    }  
    

    No matter what I try I always get an assert, but I cannot see what is causing it.

    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)
    

    解决方案

    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 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.

    For creating a new user client, you want an instance of a (kernel) 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.

    One thing you'll notice straight away is that if the IOServiceDEXTEntitlements property is missing, this won't prevent the code from succeeding:

                prop = userUC->copyProperty(gIOServiceDEXTEntitlementsKey);
                ok = checkEntitlements(entitlements, prop, NULL, NULL);
    

    and in checkEntitlements:

        if (!prop) {
            return true;
        }
    

    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 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.

    You can name this property however you want, but:

    • Its value must be a dictionary.
    • It must contain the "IOClass" key-value pair, specifying the kernel class to instantiate as a string - in your case, "IOUserUserClient"
    • It must contain the "IOUserClass" key-value pair. This specifies the dext class to instantiate, again as a string. In your case, that looks like MyUserClient.

    Putting it together:

      <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>
      …
    

    Then, from your NewUserClient function, call:

        IOService* client = nullptr;
        kern_return_t ret = this->Create(this, "MyUserClient", &client);
    

    I don't believe SUPERDISPATCH is needed here, as you presumably don't override the Create method in your class, so you super-implementation is inherited anyway.

    Then do your error checking, any other initialisation, preparation, etc. you might need, and finally:

        *userClient = client;
        return kIOReturnSuccess;
    

    这篇关于"NewUserClient"应如何设置?被实施的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆