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?
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?
Basically, this depends on what "direction" you want to go. Two approaches broad approaches, either going "up" from your io_object_t or "down" from the volume layer*:
*Note that the directionality here is entirely made up. I've always envisioned the IORegistry that grows "up" toward user space, but an argument can be made that it grows "down" from the root node.
1) Working from the USB object "up" to user space.
-
Start with your io_object_t you got from the IOServiceAddMatchingNotification.
-
Call IOServiceWaitQuiet to allow the driver stack to "stabilize". You can be notified of a USB device before the storage stack has actually loaded, so this ensure that process has occurred.
-
Move "up" the registry to find the nodes you need. What you're looking is all "IOMedia" objects with a property of "Leaf = true". Use IORegistryEntryCreateIterator(::::) with "kIORegistryIterateRecursively" to get a child iterator, then iterate all nodes looking for those two criteria.
-
That list of object will be the ones that are "eligible" for mounting. You can actually get the BSD name from the registry properties, but what I actually suggest is that you pass those IOMedia objects into DADiskCreateFromIOMedia().
-
DiskArb is what handles automounting on macOS and, what makes it useful to you is that it's neatly bridges between IOKit (io_object_t's), BSD (dev nodes), and mounts (mount points). Given a DADisk, you can find out anything you want to know by grabbing it's description dictionary and looking at the key you want. Most of those properties are available through other APIs, but DiskArb is the one API that covers "all" of them.
2) Working "down" from DiskArb into the kernel.
-
DiskArb can be used to monitor mounts and you can also create a DADisk from a mountpoint or a BSD name. With a DADisk as a starting point.
-
Use DADiskCopyIOMedia() to retrieve the IOMedia object for that disk.
-
Use IORegistryEntryCreateIterator(::::) with "kIORegistryIterateRecursively" and "kIORegistryIterateParents" to get a parent iterator, then iterate all all nodes looking for those two criteria.
-
Iterate the parent iterator looking for the "your" USB io_object_t.
All of that can sound a bit overwhelming but it's not as difficult as it sounds once you get your head around it. Also, it can seem like iterating the registry like this would be a performance issue but that isn't really the case. The entire IORegistry basically ends up living in wired kernel memory so, in practice, it's MUCH faster to manipulate than you might think.
__
Kevin Elliott
DTS Engineer, CoreOS/Hardware