0

I'm trying to communicate between an iPad app and a DriverKit dext, but IOServiceGetMatchingServices can't find the dext to communicate with.

I've been basing my app on this macOS example from Apple: https://developer.apple.com/documentation/driverkit/communicating_between_a_driverkit_extension_and_a_client_app

With an Objective-C wrapper iPad app around the C++ CppUserClient. I had to make a few changes to the Entitlements and some of the CppUserClient because some of the features are not available on iPadOS (different Entitlements like com.apple.developer.driverkit.communicates-with-drivers) or deprecated stuff in Apple's example code (e.g. kIOMasterPortDefault -> kIOMainPortDefault).

This line

ret = IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceNameMatching(dextIdentifier), &iterator);

succeeds, but the iterator doesn't have anything in it to open; there are no matching services. I'm sure the driver has started up though because I can see the init and Start succeeding in the console logs.

Is there some completely different way iPad apps are supposed to communicate with DriverKit? Or are there just other IOKit changes that need to be made to Apple's example macOS CppUserClient to work with iPads? Is there something like ioreg on iPadOS that I can use to see what services are running and see if the dext is there to communicate with?

thoms
  • 55
  • 5
  • Have you called `RegisterService()` in the dext at any point? `IOService` objects only participate in matching once they have been registered. – pmdj May 27 '23 at 09:00
  • A few more things you can check: 1. Xcode's debugging menu should let you see if there is a running process for your dext on the iPad. (I.e. the dext hasn't terminated prematurely) 2. Check for any crash logs. 3. In your app, match the device your dext should be matching, and iterate over the subtree of entries below it to see what's actually matched the device (if anything). (To do this, use `IORegistryEntryCreateIterator` and [`IORegistryIterator{Enter|Exit}Entry()`](https://stackoverflow.com/a/50258951/48660).) – pmdj May 27 '23 at 09:11
  • I should say that otherwise, the approach is correct. (I disagree somewhat with using `IOServiceNameMatching` - I'd worry about name clashes, so [I personally use a combination of class name and bundle ID for matching dexts](https://gitlab.com/pmdj/kextgizmos/-/blob/main/dext_userclient.c#L61). But using `IOServiceNameMatching` shouldn't be causing your matching failure.) – pmdj May 27 '23 at 09:16
  • 1
    @pmdj RegisterService() being missing was exactly it; thanks! I'm able to open the Service, but I guess there's still some behavior that I wasn't expecting around the dext already having launched itself and called Start() after plugging in the USB device, and the IOServiceOpen calling Start again with no provider. I suppose I need to separate the actual driver class and the IOUserClient, where the example code has them be the same since it's not USBDriverKit? Maybe time for a new question... – thoms Jun 01 '23 at 13:24
  • Yeah, the example's reuse of the same class as its own user client is *very* odd, and not something I've ever seen in a shipping driver, and certainly not something I've ever done in any of the drivers I've developed. I assume the intention is to cut down on code in the sample, but in my opinion it just makes things more confusing for beginners. – pmdj Jun 01 '23 at 13:27

1 Answers1

0

For an IOService object to become eligible for matching, RegisterService() must be called on it. Essentially, this signals to the rest of the system that the object is ready for clients to connect to it, be they other kernel or DriverKit IOService nodes, or user clients that wish to connect with IOServiceOpen().

pmdj
  • 22,018
  • 3
  • 52
  • 103