I've always attributed slow Xcode launches to Xcode simply sucking, but I've noticed that the FileMerge app frequently launches slowly too. When this happens, the app can take a dozen bounces in the Dock before finally opening. FileMerge resides in the folder Xcode.app/Contents/Applications/ within the Xcode bundle and can be opened from the Xcode main menu under the Open Developer Tool submenu. I actually keep FileMerge in my Dock for quick access, because I use FileMerge a lot for diffing files and folders. I finally got fed up with slow launches and decided to investigate by taking a spindump from Activity Monitor. Spindumps are a nice way to see what exactly is consuming resources on your Mac, because they show the "CPU Time" used by each process on your system and each thread in the process.
From the spindump I discovered that the slow launches are caused by the syspolicyd process, specifically DispatchQueue "com.apple.security.syspolicy.yara". The backtrace showed syspolicyd calling the yr_rules_scan_file function. According to Wikipedia:
YARA is the name of a tool primarily used in malware research and detection. It provides a rule-based approach to create descriptions of malware families based on regular expression, textual or binary patterns.
Thus, macOS is periodically scanning FileMerge for malware on launch, which causes very slow app launches. I don't know what the exact period is between scans, but rebooting the Mac seems to reset the cache, which made it convenient for me to test the malware scans while writing this blog post (but otherwise makes it extremely inconvenient for me). I've noticed the same syspolicyd malware scanning and consequent slow launches with some other apps such as Xcode itself, Google Chrome, and Wireshark. You can even see syspolicyd spinning up % CPU in Activity Monitor when the malware scan happens. (In order to catch this, make sure to increase Update Frequency to 1 sec.)
Xcode, Chrome, and Wireshark are very large apps, so it makes sense that a malware scan of them would be slow. However, FileMerge is much smaller, only 2 MB. Why does that take so long? My theory is that syspolicyd also scans the launched app's linked libraries. The command otool -L in Terminal will show them:
otool -L /Applications/Xcode.app/Contents/Applications/FileMerge.app/Contents/MacOS/FileMerge
I doubt that the built-in system libraries are scanned for malware, because they reside on a separate cryptographically-signed read-only disk volume. But FileMerge also links to non-system libraries:
@rpath/IDEFoundation.framework/Versions/A/IDEFoundation (compatibility version 1.0.0, current version 22551.0.0)
@rpath/DVTKit.framework/Versions/A/DVTKit (compatibility version 1.0.0, current version 1.0.0)
@rpath/DVTFoundation.framework/Versions/A/DVTFoundation (compatibility version 1.0.0, current version 1.0.0)
@rpath/DeltaFoundation.framework/Versions/A/DeltaFoundation (compatibility version 1.0.0, current version 1.0.0)
@rpath/DeltaKit.framework/Versions/A/DeltaKit (compatibility version 1.0.0, current version 1.0.0)
@rpath/DVTUserInterfaceKit.framework/Versions/A/DVTUserInterfaceKit (compatibility version 1.0.0, current version 1.0.0)
@rpath/libXCTestSwiftSupport.dylib (compatibility version 1.0.0, current version 22516.0.0, weak)
These libraries are located within the Xcode bundle in the Xcode.app/Contents/SharedFrameworks/ folder.
In my testing, I also saw somewhat slow launching from another app bundled with Xcode, Accessibility Inspector. This app is larger than FileMerge, yet it launches much more quickly. I suspect the reason is that it links to fewer Xcode frameworks:
@rpath/AccessibilitySupport.framework/Versions/B/AccessibilitySupport (compatibility version 0.0.0, current version 0.0.0)
@rpath/DVTFoundation.framework/Versions/A/DVTFoundation (compatibility version 1.0.0, current version 1.0.0)
@rpath/DVTKit.framework/Versions/A/DVTKit (compatibility version 1.0.0, current version 1.0.0)
@rpath/AccessibilityAudit.framework/Versions/B/AccessibilityAudit (compatibility version 1.0.0, current version 1.0.0)
@rpath/AccessibilityAuditDeviceManager.framework/Versions/A/AccessibilityAuditDeviceManager (compatibility version 1.0.0, current version 1.0.0)
In case you're wondering, Apple hasn't exempted Mac App Store apps from malware scanning, not even its own apps. I downloaded Xcode from the Apple Developer website rather than from the Mac App Store, but I can see the syspolicyd malware scan when launching large Mac App Store apps such as Pages and Numbers. Again, though, I think that the built-in read-only system apps are exempt.
Here's a mystery: I see frequent slow launches and malware scans with Google Chrome but never with Google Chrome Beta, despite the fact that the Google Chrome beta app is about the same size as the Google Chrome app. I don't yet have an explanation for the difference in behavior.
By the way, the existence or nonexistence of extended attributes such as com.apple.quarantine makes no difference. Removing all the extended attributes from an app bundle doesn't stop the malware scans.
You may remember our friend syspolicyd as the process that phones home to Apple when running unsigned executables. It was also the culprit in making Xcode tools slow after reboot. I guess I should have already known the cause of the slow app launches, but I must have forgotten and/or failed to put two and two together. In any case, syspolicyd sucks, and I really wish there were a way to completely disable the malware scanning and allow my apps to always launch quickly. I'm very careful about what I install, and I've never had malware in over twenty years of full-time Mac usage, so I think it's safe to say that for me, syspolicyd is security theater, and I'd rather not have to sit through its "play", full of sound and fury, signifying nothing. To be fair, I don't have an issue with malware scanning in the background; I just don't want malware scanning to hold up my apps launching in the foreground. Instead of interrupting me and scanning an app during the seconds when I'm launching it—what should be a fraction of a second—how about scanning the app during the innumerable seconds when I'm not launching it?
Perhaps disabling System Integrity Protection disables the malware scan too? I haven't checked this, but it's not really viable for me as a Mac software developer, because I need to test the same runtime environment as my users, otherwise I could write code that works for me but not for my users. I believe that disabling SIP also disables some Apple services on your Mac that are "protected" by DRM (in order to make reverse engineering more difficult).
I've now confirmed that disabling SIP does indeed eliminate the syspolicyd malware scan. Xcode launches so fast, it's beautiful. I feel like I'm in heaven! I don't think I can go back to the previous hell. I'll live with the consequences, whatever they may be.