Как должен быть реализован «NewUserClient» - PullRequest
1 голос
/ 01 мая 2020

Я пытаюсь взаимодействовать с dext из приложения. Я могу найти службу, используя IOServiceOpen, и я получаю вызов NewUserClient моего dext (я вижу, что переданный параметр 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:

Изобретательность конструкции 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)

1 Ответ

1 голос
/ 03 мая 2020

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

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

Для создания нового пользовательского клиента вам необходим экземпляр подкласса (kernel) IOUserClient, который поддерживается вашим (dext) IOUserClient подкласс. Класс ядра для этого на самом деле IOUserUserClient. (Да, действительно.) Как вы обнаружили, в документации не совсем ясно, как вы go об этом. Мне показалось полезным взглянуть на то, что доступно с точки зрения исходного кода - сторона вызова NewUserClient в ядре реализована в функции IOUserServer::serviceNewUserClient() здесь .

Одна вещь, которую вы Вы сразу заметите, что если свойство IOServiceDEXTEntitlements отсутствует, это не помешает выполнению кода:

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

и checkEntitlements:

    if (!prop) {
        return true;
    }

Это отличная новость, так как это означает, что нам не нужно беспокоиться об этом ни на минуту, и мы можем просто ее отключить.

Далее получается, что propertiesKey относится к свойству на провайдере IOUserService объект ядра . Вы не можете установить эти свойства внутри кода dext, поэтому единственный способ предоставить их - из словаря соответствия личности IOKit.

Вы можете назвать это свойство по своему усмотрению, но:

  • Его значение должно быть словарем.
  • Оно должно содержать пару ключ-значение "IOClass", определяющую класс 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* client = nullptr;
    kern_return_t ret = this->Create(this, "MyUserClient", &client);

Я не верю, что SUPERDISPATCH здесь необходим, так как вы, вероятно, не переопределяете метод Create в своем классе, так что ваша супер-реализация все равно наследуется.

Тогда сделайте вашу ошибку проверка, любая другая инициализация, подготовка и т. д. c. вам может понадобиться, и наконец:

    *userClient = client;
    return kIOReturnSuccess;
...