Use IOKit to access usb in MacOS

Hi, I am trying to develop MacOS application which will be connecting to USB devices and should be available in AppStore. So it must be Sandbox and probably I've to use permission com.apple.security.device.usb.

I've following requirements:

  • I need to detect USB devices with file system
  • I need to have ability to upload & download files from this device
  • I need to read device serial number

I wonder if I can use IOKit for this and it will be compliant with AppStore rules or not?

Answered by DTS Engineer in 814287022

I saw they are using IOKit somehow, but I'm not sure it is used for this.

So, the first thing to understand here is that IOKit is basically THE API here. Other frameworks are often built on top/around it (more on that shortly), but IOKit is the core of how hardware is discovered and accessed from user space.

Case in point:

For generic Kindle, right now we are using system_profiler SPUSBDataType -xml for detection

Basically "all" of the hardware specific information you see in system_profiler was actually pulled from the IORegistry using IOKit. A few things I'd recommend when you're getting started with IOKit:

  1. Take a close look at the documents "IOKit Fundamentals". This is document is the "base" reference for how IOKit (the kernel API) is structured and functions and will help you understand what you're seeing on a "real world" system.

  2. Download and experiment with "IORegistryExplorer.app", which you'll find in side the "Additional Tools for Xcode <version>". Note that while that download is versioned to Xcode, you don't really need to worry about staying "current". IORegistryExplorer.app itself changes VERY little- the app itself is 24+ years old but is only at v3.0.2 and I don't think it's been updated since 2013. In any case, what IORegistryExplorer.app actually shows you is the system "IORegistry" structure, which is the core of how IOKit hardware discovery and communication works. Note that the data you're actually seeing in SPUSBDataType call came from the IORegistry data store.

  3. Read "Accessing Hardware From Applications", which is the reference for using the IOKit (user space) API to interact with hardware. It describes how you'll actually discover hardware and retrieve information about it.

I would be happy to hear if you have a recommendation for APIs

In terms of the API side of this, the basic approach would be:

  1. Use IOKit to discover existing devices and monitor for new ones, then determine whether your app should interact with them based on the devices properties. You can find some basic code in this post showing what this looks like. Note that it is ONLY a simple starting point. For example, it uses "IOServiceGetMatchingServices" (which searches for registry) but an app would use "IOServiceAddMatchingNotification" (which finds current services and then monitors for new ones).

  2. Based on the serial number (retrieved in #1), you'd then either use file systems access or device access.

  3. The file system access operates entirely outside of IOKit. IOKit (and other APIs) can be used to determine what mount point corresponds to a particular hardware device but all of the actual "access" would be handled just like any other file access.

  4. For MTP access, the IOKit object from #1 would then be used to directly communicate with the device through the IOUSBHost framework. Note that while the framework uses the term "host-mode user space drivers", that is a very fancy way of saying "an app that directly controls device".

that are compatible with AppStore's policy.

In terms of sandbox compatibility, I think the "com.apple.security.device.usb" entitlement is the main one you'd need. What's allowed on the App Store is ultimately determined by App Review, but I don't think any thing I've described above would be an issue on the App Store.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Hi, I am trying to develop MacOS application which will be connecting to USB devices and should be available in AppStore. So it must be Sandbox and probably I've to use permission com.apple.security.device.usb.

I think this is a case where I need a much better understanding of what you're actually trying to do and why.

The problem with what you're asking here:

I've following requirements:

I need to detect USB devices with file system I need to have ability to upload & download files from this device I need to read device serial number

...is that it sounds like what you'd like to do is attach a USB device to your mac and transfer (up or down) a file(s) to it without directly over USB, without using any "higher level" API.

If that's the case then:

  • In theory, it's entirely possible. Strictly speaking, the IOUSBHost framework will allow you to exchange USB traffic with device. Exchanging USB traffic is all any USB device does so, sure, it's possible.

  • In practice, it's somewhere between "an enormous pain" and "wildly impractical", depending on exactly how narrow what you're trying to do is and what code you already have. I'm happy to outline what's required, but it's directly equivalent to creating an entire mass storage stack from "scratch".

I wonder if I can use IOKit for this and it will be compliant with AppStore rules or not?

Again, this really depends on what you're actually trying to do. I can think of many approaches that would be App Store compatible. However, the problem wouldn't be getting them on the store, it would be getting them to work at all.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Ok so here is the whole idea.

Right now we have working code for that solution, but it isn't code compliant with AppStore

Here are some specs:

  • MacOS app available in AppStore - our current code is working without sandbox
  • App will be connecting with Kindle devices. Amazon currently is using both approaches - file system (older devices), MTP (new devices)
  • App needs to detect Kindle device - both types as described above
  • I have PoC for MTP solution using libmtp library, now looking for a solution for a generic Kindle
  • I need to read attached device serial number to identify it in our system
  • Ability to download/upload files from specific directory on device

So in general app is:

  • Listening if some usb devices are connecting
  • Checking if it is old type Kindle device using FS or new one using MTP
  • Reading serial number to identify device
  • Copying/deleting/reading files from documents

I've seen that there is for instance app called Commander One in AppStore which is working with USB and have most of the functions above. Only reading serial number is missing there.

I saw they are using IOKit somehow, but I'm not sure it is used for this. For generic Kindle, right now we are using system_profiler SPUSBDataType -xml for detection

I would be happy to hear if you have a recommendation for APIs that are compatible with AppStore's policy.

Accepted Answer

I saw they are using IOKit somehow, but I'm not sure it is used for this.

So, the first thing to understand here is that IOKit is basically THE API here. Other frameworks are often built on top/around it (more on that shortly), but IOKit is the core of how hardware is discovered and accessed from user space.

Case in point:

For generic Kindle, right now we are using system_profiler SPUSBDataType -xml for detection

Basically "all" of the hardware specific information you see in system_profiler was actually pulled from the IORegistry using IOKit. A few things I'd recommend when you're getting started with IOKit:

  1. Take a close look at the documents "IOKit Fundamentals". This is document is the "base" reference for how IOKit (the kernel API) is structured and functions and will help you understand what you're seeing on a "real world" system.

  2. Download and experiment with "IORegistryExplorer.app", which you'll find in side the "Additional Tools for Xcode <version>". Note that while that download is versioned to Xcode, you don't really need to worry about staying "current". IORegistryExplorer.app itself changes VERY little- the app itself is 24+ years old but is only at v3.0.2 and I don't think it's been updated since 2013. In any case, what IORegistryExplorer.app actually shows you is the system "IORegistry" structure, which is the core of how IOKit hardware discovery and communication works. Note that the data you're actually seeing in SPUSBDataType call came from the IORegistry data store.

  3. Read "Accessing Hardware From Applications", which is the reference for using the IOKit (user space) API to interact with hardware. It describes how you'll actually discover hardware and retrieve information about it.

I would be happy to hear if you have a recommendation for APIs

In terms of the API side of this, the basic approach would be:

  1. Use IOKit to discover existing devices and monitor for new ones, then determine whether your app should interact with them based on the devices properties. You can find some basic code in this post showing what this looks like. Note that it is ONLY a simple starting point. For example, it uses "IOServiceGetMatchingServices" (which searches for registry) but an app would use "IOServiceAddMatchingNotification" (which finds current services and then monitors for new ones).

  2. Based on the serial number (retrieved in #1), you'd then either use file systems access or device access.

  3. The file system access operates entirely outside of IOKit. IOKit (and other APIs) can be used to determine what mount point corresponds to a particular hardware device but all of the actual "access" would be handled just like any other file access.

  4. For MTP access, the IOKit object from #1 would then be used to directly communicate with the device through the IOUSBHost framework. Note that while the framework uses the term "host-mode user space drivers", that is a very fancy way of saying "an app that directly controls device".

that are compatible with AppStore's policy.

In terms of sandbox compatibility, I think the "com.apple.security.device.usb" entitlement is the main one you'd need. What's allowed on the App Store is ultimately determined by App Review, but I don't think any thing I've described above would be an issue on the App Store.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Thank you very much - very helpful :) I've already made some progress yesterday in terms of discovering devices. I'll go further with this.

Maybe one more question. I was able to get RawUsbDevice using IOServiceAddMatchingNotification and now have basic stuff like VendorID, ProductID, SerialNo etc.

How to get bsd name for this object or even mount point like /Volumes/Kindle/ in Sandboxed app?

Earlier I was able to read bsd name using system profiler, but this particular data is not available when Sandbox is used.

I can read mount point using mountedVolumeURLsIncludingResourceValuesForKeys on NSFileManager but can't match mount point to specific RawUsbDevice gathered from IOKIt.

Use IOKit to access usb in MacOS
 
 
Q