What happens when you double-click a document? Processes, problems and solutions

One of the most revolutionary and magical features of the Mac human interface is that you can double-click on any document and it will automagically be opened in the app currently designated as your editor for that file. In Classic days, this was implemented by assigning each file a type and creator code, which then related through a hidden Desktop database to the app which would open files of that type. Amazingly, macOS 10.15 Catalina still incorporates support for those old type and creator codes, but has moved on to more sophisticated systems centred on LaunchServices.

Essentially similar processes occur when you open a document using other methods provided by the Finder, including its Open command, which are acted upon by LaunchServices and related sub-systems.

What the document needs

Every file system object on your Mac, including all its documents and other files, has a designated UTI (Uniform Type Identifier), which looks something like a URL. For a PDF document, for example, the UTI is com.adobe.pdf. The overriding way in which this is set is using the filename extension, in this case pdf. The system also matches that with a MIME type, often used by servers to designate the type of content, here application/pdf. There’s even an old Classic file type associated, 'PDF '.

If the file has the wrong UTI – for instance, if you change its extension from pdf to text – the system will try to open it with the wrong app. Further details are given here. You can explore UTIs and other types of identifier using my free tool UTI Utility.

What the app needs

When developers build apps, among the many things they include is a list of document types which that app can open and/or edit. These specify the OS type, extensions, and UTI of each type of document, and are baked into the app’s Info.plist file. Because that’s one of the key files sealed when the app is signed, you can’t alter that. The other key piece of information is of course that app’s bundle identifier, the reverse-URL name used to identify the app, such as co.eclecticlight.Podofyllin for my PDF viewer Podofyllin.

When that app is installed on your Mac, its Info.plist file is checked and information extracted and added to what are commonly known as LaunchServices databases. These match each app against the UTIs which they can open and edit. For each UTI, one app is designated as the default to open documents of that kind; for PDF, that’s normally Preview. You can change that default in the Finder’s Get Info dialog, and set any individual document to be opened by a different app if you wish.

Setting a single document to be opened by a different app adds an extended attribute of type com.apple.LaunchServices.OpenWith to that document. That contains the app identifier, its path, and any specific version to be used. If you strip those extended attributes from documents, they will all revert to being opened by the default editor for that UTI.

The Desktop databases in Classic Mac OS periodically used to become corrupted. One easy way to tell they were getting into trouble was when custom icons were replaced by generic versions, something which still occasionally happens even in Catalina. In Classic Mac OS, you then had to force the Desktop database to be rebuilt from scratch, which restored normal function.

Although the LaunchServices databases do sometimes become damaged, this is now unusual, and you should never have to force them to be rebuilt in recent versions of macOS. One more common issue that can arise is that LaunchServices opens the right type of app, but the wrong version, when you have multiple versions stored on the same Mac. You may be able to fix that by first using lsregister from the path /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister to dissociate an app version stored at pathname in
lsregister -R -f -u pathname
then using
lsregister -R -f pathname2
to register the preferred copy at pathname2. Thanks to Jeff Johnson for pointing this out.

If all else fails, you can reset the LaunchServices database using
lsregister -kill
or delete it altogether using
lsregister -delete
following which you’ll need to restart and wait for it to be rebuilt. That’s a drastic solution which shouldn’t be used lightly, and sometimes causes even more trouble.

Double-click the document

In Catalina, much of the process of opening a document from a double-click is omitted from the unified log. However, if you do try to follow it, the landmarks to look for are given in this summary.

Double-clicking doesn’t normally appear in regular log entries, but as activities:
0.920235 sendAction:
given as time in seconds and the message in the log.

The Finder identifies the document which the user wishes to open, and passes that for its UTI to be resolved. This used to be handled by LaunchServices, but now appears to be the responsibility of the QuickLookUIHelper app in the Quartz framework in macOS. This makes sense, as it’s QuickLook which is responsible for using the UTI to work out whether to display a document-specific icon or a QuickLook thumbnail. So the first thing you’ll see in the log is that app being started, with entries such as
0.957049 com.apple.launchservices LSApplicationCheckIn(), app being registered is:"/System/Library/Frameworks/Quartz.framework/Versions/A/Frameworks/QuickLookUI.framework/Versions/A/Resources/QuickLookUIHelper.app/Contents/MacOS/QuickLookUIHelper"
0.957452 com.apple.launchservices { "ApplicationType"="BackgroundOnly", "BuildMachineOSBuild"="18A391012", "CFBundleDevelopmentRegion"="English", "CFBundleExecutable"="QuickLookUIHelper", "CFBundleExecutablePath"="/System/Library/Frameworks/Quartz.framework/Versions/A/Frameworks/QuickLookUI.framework/Versions/A/Resources/QuickLookUIHelper.app/Contents/MacOS/QuickLookUIHelper" …
0.988141 com.apple.launchservices CFDictionaryRef FindApplicationInformationDictionaryGivenASNUsingLocalCache(LSSessionID, LSASNRef)(), information in shared memory with seed 520 was still valid, so using cached info { "ApplicationType"="BackgroundOnly", "BuildMachineOSBuild"="18A391012", "BundleIdentifierLowerCase"="com.apple.quicklook.ui.helper", "CFBundleDevelopmentRegion"="English", "CFBundleExecutable"="QuickLookUIHelper", "CFBundleExecutablePath"="/System/Library/Frameworks/Quartz.framework/Versions/A/Frameworks/QuickLookUI.framework/Versions/A/Resources/QuickLookUIHelper.app/Contents/MacOS/QuickLookUIHelper" …

Once the document’s UTI has been matched with an app, the log records it, unfortunately censoring the crucial information:
0.986924 com.apple.launchservices Opening document <private> with application <private>

If that app is already running, Launch Services then sends it an AppleEvent requesting the app to open the document. If not, the next job is to start the app. The log entries marking that are long but informative, as they reveal details of the app:
0.992147 com.apple.launchservices LaunchApplication: appToLaunch={ "ApplicationType"="Foreground", "CFBundleExecutablePath"="/Applications/Podofyllin.app/Contents/MacOS/Podofyllin", "CFBundleExecutablePathDeviceID"=16777233, "CFBundleExecutablePathINode"=29050739, "CFBundleIdentifier"="co.eclecticlight.Podofyllin", "CFBundleName"="Podofyllin", "CFBundlePackageType"="APPL", "LSApplicationLockedInStoppedStateKey"=true, "LSBundlePath"="/Applications/Podofyllin.app", …
1.298523 com.apple.launchservices CFDictionaryRef FindApplicationInformationDictionaryGivenASNUsingLocalCache(LSSessionID, LSASNRef)(), information in shared memory with seed 530 was still valid, so using cached info { "ApplicationType"="Foreground", "BuildMachineOSBuild"="18F132", "BundleIdentifierLowerCase"="co.eclecticlight.podofyllin", "CanBecomeFrontmost"=true, "CFBundleDevelopmentRegion"="en", "CFBundleDocumentTypes"=( { "CFBundleTypeExtensions"=( "[pdf]"), "CFBundleTypeName"="PDFType", "CFBundleTypeOSTypes"=( "????"), "CFBundleTypeRole"="Editor", "LSItemContentTypes"=( "com.adobe.pdf"), "NSDocumentClass"="Podofyllin.Document" }), "CFBundleExecutable"="Podofyllin", "CFBundleExecutablePath"="/Applications/Podofyllin.app/Contents/MacOS/Podofyllin", "CFBundleExecutablePathDeviceID"=16777233, "CFBundleExecutablePathINode"=29050739, "CFBundleIconFile"="AppIcon", "CFBundleIconName"="AppIcon", "CFBundleIdentifier"="co.eclecticlight.Podofyllin", "CFBundleInfoDictionaryVersion"="6.0", "CFBundleName"="Podofyllin", "CFBundleNameLowerCase"="podofyllin", "CFBundleNumericVersion"=16809984, "CFBundlePackageType"=<…>

The latter log entry contains the key information: the app’s bundle identifier, and its document types including the UTI. Launch Services has performed the match correctly.

Launch of that app then proceeds: in Catalina that involves a shortened Gatekeeper check for malware, thorough checking by TCC for privacy entitlements, and initiation of monitoring by RunningBoard. Opening the document which you double-clicked is instigated by an AppleEvent sent from LaunchServices, which in turn triggers any checks required if the document has its quarantine flag set (as many do), before the app finally opens the document ready for you to see and edit.

Occasionally, security checks on a document can result in an error, even though the rest of this system appears to have worked correctly. This is explained here.

Here’s a summary chart of the steps involved:

DoubleClickDocument1

and a tear-out PDF for download from: DoubleClickDocument1