Как следует реализовать "NewUserClient"

Я пытаюсь взаимодействовать с декстом из приложения. Я могу найти сервис, используяIOServiceOpen и мне звонят NewUserClient моего декста (я вижу typeпереданный параметр выводится в журнал). После этого я немного заблудился. Читая здесь о NewUserClient, я вижу, что следует использовать Create для создания нового объекта Service.

Обсуждение часть здесь говорит ключи вpropertiesKey словарь описать новую услугу.

Если этот словарь быть помещен в файл plist для расширения системы как запись верхнего уровня, или если словарь должен быть помещен с ключом в IOKitPersonalities?

Могу я оставить IOServiceDEXTEntitlements ключ с пустым значением, чтобы не накладывать никаких ограничений на права для приложения, которое подключается к расширению системы?

Мой список выглядит так (с 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?

Из главы 5 "Программирование ядра OSX и iOS" на стр. 81:

Изобретательность дизайна набора I/O Kit состоит в том, что пользовательские клиентские объекты сами являются объектом драйвера: класс IOUserClient наследуется от IOService, и, как и в случае с любым другим экземпляром IOService, каждый пользовательский клиент имеет класс провайдера, который для пользовательского клиента является экземпляр драйвера, которым управляет приложение.

Хотя приведенное выше может быть правильным только для kext (?), Я бы предположил, что все работает таким же образом для dext,

Из документации Create: используйте ключ kIOUserClassKey, чтобы указать имя настраиваемого подкласса IOService, экземпляр которого вы хотите создать в системе.

Почему другой IOServiceкласс нужно создать? Какова цель этого занятия? Это поставщик моего класса, который наследуется отIOUserClient? Если да, то как я могу создать экземпляр моего драйвера (тот, который реализуетNewUserClient) провайдер?

Из документации Create: используйте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)

1 ответ

Решение

Несмотря на то, что презентация WWDC на DriverKit пыталась притвориться иначе, взгляд DriverKit на мир сильно отличается от взгляда ядра, и вам нужно знать некоторые детали реализации, потому что абстракция очень нечеткая.

Как вы, наверное, уже заметили, то, что выглядит как IOService объект в вашем драйвере DriverKit на самом деле IOUserServiceобъект в представлении ядра (и пользовательского пространства) реестра ввода-вывода. Пробел устраняется с помощью механизма IPC DriverKit.

Для создания нового пользовательского клиента вам нужен экземпляр (ядра) 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объект ядра. Вы не можете установить эти свойства из кода декста, поэтому единственный способ предоставить их - из соответствующего словаря личности 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;
Другие вопросы по тегам