fix(mtp): release the MTP interface from macOS' Image Capture daemons - #483
Open
hariantara wants to merge 1 commit into
Open
fix(mtp): release the MTP interface from macOS' Image Capture daemons#483hariantara wants to merge 1 commit into
hariantara wants to merge 1 commit into
Conversation
Fixes the long-standing "device not detected while adb still sees it" case
on macOS, where the only known workaround was restarting the machine.
macOS starts `ptpcamerad` and `mscamerad-xpc` on demand for any device that
exposes an MTP/PTP interface, and they hold that interface exclusively:
USB: Open, err: <nil>
USB: ClaimInterface 0x0, err: LIBUSB_ERROR_ACCESS
MTP sendreq failed: LIBUSB_ERROR_NOT_FOUND
error initializing: OpenSession after reset: LIBUSB_ERROR_NOT_FOUND
which reaches the UI as ErrorDeviceSetup. The device stays fully visible to
`adb devices` throughout, because adb speaks to a different interface on the
same device, which is what makes this so hard to recognise.
Verified on a Redmi Note 15 5G (2717:ff48, MTP+ADB) on macOS 15.7:
- reproduces with the app closed, so it is not an OpenMTP session leak
- killing only those two daemons, with adb left running, makes
ClaimInterface return nil and the device enumerate fully
- so adb is not the cause, despite being what users notice first
Two details matter, and both were found the hard way:
- SIGKILL, not SIGTERM. Both daemons ignore SIGTERM while pkill still
exits 0 for having signalled them, which reports a successful release
while nothing has changed.
- No delay before the retry. launchd restarts them within milliseconds
and they reclaim the interface immediately, so the handshake has to
follow the release with nothing awaited in between.
The daemons are only touched after a handshake has already failed, never
pre-emptively, and are matched by exact process name so nothing else is
affected. Both run as the current user and launchd restarts them on demand,
so ending them is safe and reversible.
Relates to ganeshrvel#396, ganeshrvel#276.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
On recent macOS, the device intermittently isn't detected — either nothing appears, or Refresh shows "An error occured while setting up the Phone" — while
adb devicesstill lists the phone perfectly. The only known workaround has been restarting the Mac.This looks like a bug in OpenMTP, but it isn't.
Cause
macOS starts
ptpcameradandmscamerad-xpcon demand for any device exposing an MTP/PTP interface, and they hold that interface exclusively. While they hold it:which surfaces as
ErrorDeviceSetup.The device stays fully visible to
adbthe entire time, because adb speaks to a different USB interface on the same device. That's what makes this so hard to recognise — everything suggests the phone is fine and the app is broken.Evidence
Tested on a Redmi Note 15 5G (
2717:ff48, MTP+ADB) on macOS 15.7, Apple Silicon:kalam_debug_report— so it isn't a stale session or a leaked handle inside the app.ClaimInterfacereturnniland the device enumerate fully (240 GB storage listed).Fix
After a handshake fails, release the interface and retry.
Two details matter, and both cost me a while to find:
SIGKILL, notSIGTERM. Both daemons ignoreSIGTERMand survive with their original PIDs, whilepkillstill exits 0 for having signalled them — so the release reports success while changing nothing.launchdrestarts them within milliseconds and they reclaim the interface immediately. The handshake has to follow the release with nothing awaited in between. An earlier version slept 500ms here and lost the race every single time.Safeguards:
pkill -x), not command line —pkill -fis far too broad and would also match unrelated daemons such asappleh13camerad.releaseMtpInterfaceClaimants()logs what it did, so this is diagnosable from a packaged build.Testing
Verified on the hardware above, with the daemons confirmed holding the interface before launch:
ErrorDeviceSetup; daemon PIDs unchanged.kalam_debug_reportthen getsLIBUSB_ERROR_ACCESS, i.e. OpenMTP has the device.Scope
Three files,
+140/-2. No dependency changes and no rebuild of the Kalam dylib — it goes through the existing exportedDispose/Initialize.Relates to #396 and #276, and likely a number of the other "not recognized on macOS" reports.