Mac OS X Internals: A Systems Approach

7.6. Launching Applications

Users typically create new processes by launching applications through the graphical user interfacefor example, through the Finder or the Dock. The Launch Services framework, which is a subframework of the Application Services umbrella framework, provides primary support for application launching. Launch Services allows programmatic opening of executables, documents,[22] and other entities either by file system references or by URL references. The framework provides functions such as the following.

[22] A document is launched by running the appropriate executable to handle the document.

  • LSOpenFSRef() opens a file residing on a local or remote volume.

  • LSOpenFromRefSpec(), which is a more general function than LSOpenFSRef(), is called by the latter.

  • LSOpenCFURLSpec() opens a URL. Note that a URL could be a file: URL that refers to a file on a volume.

  • LSOpenFromURLSpec(), which is a more general function than LSOpenCFURLSpec(), is called by the latter.

The Cocoa NSWorkspace class uses the Launch Services framework to launch applications. Launch Services eventually performs a fork() and an execve().

7.6.1. Mapping Entities to Handlers

Applications can register themselves with Launch Services to advertise their ability to open documents of a certain type. Such ability can be specified by file extension, by URL scheme, and, more appropriately, through a generalized data identifier scheme called Uniform Type Identifiers (UTIs).[23] We will look at UTIs in the next section.

[23] Although UTI support was introduced in Mac OS X 10.3, comprehensive UTI support is available only beginning with Mac OS X 10.4.

Typically, registration with Launch Services occurs automatically, without requiring any action from the user. For example, it could occur at the following times:

  • When the system is booted

  • When a user logs in

  • When the Finder locates a new application, such as on a newly mounted disk imagesay, one that has been downloaded from the Internet

When examining the output of the ps command, you can see that the parent of processes corresponding to GUI-based applications is the WindowServer program. When a user launches a GUI-based application through the Finder, Launch Services sends a message to WindowServer, which in turns calls fork() and execve() to run the requested application. You can use the kdebug program from Chapter 6 to monitor the invocation of fork() by WindowServer.

In particular, the AppServices startup item (/System/Library/StartupItems/AppServices/AppServices) runs the lsregister programa support tool that resides within the Launch Services framework bundleto load the Launch Services registration database. lsregister can also dump the contents of a registration database fileeach user has a separate database stored as /Library/Caches/com.apple.LaunchServices-*.csstore. Figure 761 shows an example of using lsregister.

Figure 761. Dumping the Launch Services registration database

$ lsregister -dump Checking data integrity......done. Status: Database is seeded. ... bundle id: 44808 path: /Applications/iWork/Keynote.app name: Keynote identifier: com.apple.iWork.Keynote version: 240 mod date: 5/25/2005 19:26:46 type code: 'APPL' creator code: 'keyn' sys version: 0 flags: apple-internal relative-icon-path ppc item flags: container package application extension-hidden native-app scriptable icon: Contents/Resources/Keynote.icns executable: Contents/MacOS/Keynote inode: 886080 exec inode: 1581615 container id: 32 library: library items: -------------------------------------------------------- claim id: 30072 name: Keynote Document role: editor flags: apple-internal relative-icon-path package icon: Contents/Resources/KeyDocument.icns bindings: .key, .boom, .k2 -------------------------------------------------------- claim id: 30100 name: Keynote Theme role: viewer flags: apple-internal relative-icon-path package icon: Contents/Resources/KeyTheme.icns bindings: .kth, .bth, .kt2 ...

Consider the situation when an application wants to handle a document or URL type that is already registered in the Launch Services database. Launch Services considers several aspects before selecting a candidate. A handler explicitly specified by the user takes the highest precedence. An application on the boot volume is preferred over applications on any other volumesthis is important to avoid running potentially malicious handlers from untrusted volumes. Similarly, an application on a local volume is preferred over those on remote volumes.

7.6.2. Uniform Type Identifiers

A Uniform Type Identifier (UTI) is a Core Foundation stringfor example, "public.html" or "com.apple.quicktime-image"that uniquely identifies an abstract type. Mac OS X uses UTIs to describe data types and file formats. In general, a UTI can be used to describe arbitrary type information about in-memory or on-disk entities, such as aliases, files, directories, frameworks, other bundles, and even in-transit data. Since UTIs provide a consistent mechanism for tagging data, services and applications should use UTIs to specify and recognize data formats that they support. The following are examples of using UTIs.

  • Applications can use UTIs to register with Launch Services the document types they wish to handle. The UTI API is part of the Launch Services API.

  • The Pasteboard Manager can use UTIs to specify flavors for items it holds, where a flavor identifies a particular data type. Each pasteboard item can be represented by one or more flavors, allowing different applications to retrieve the item's data in formats convenient to them.

  • Navigation Services allows the use of UTIs for filtering file types.

A UTI string is syntactically similar to a bundle identifier. UTIs are written using a reverse DNS naming scheme, with certain top-level UTI domains being reserved for Apple's use.[24] For example, Apple declares types that it controls with identifiers in the com.apple domain. Public typesthat is, those types that either are public standards or are not controlled by an organizationare declared with identifiers in the public domain. Third parties should use Internet domains they own for declaring their UTIsfor example, com.companyname. The use of a reverse DNS naming scheme ensures uniqueness without centralized arbitration.

[24] Such domains are outside the current IANA top-level Internet domain name space.

The Apple-reserved domain dyn is used for dynamic identifiers that are automatically created on the fly when a data type with no declared UTI is encountered. The creation of dyn UTIs is transparent to users. An example of a file whose content type is a dyn UTI is a .savedSearch filethese files correspond to Smart Folders and contain raw Spotlight queries.

The information property list file of /System/Library/CoreServices/CoreTypes.bundle contains specifications of various standard UTIs. For example, we can list the public types contained in that file as follows:

$ cd /System/Library/CoreServices/CoreTypes.bundle $ awk '{ if (match ($1, /public\.[^<]*/)) { \ substr($1, RSTART, RLENGTH); } }' Info.plist | sort | uniq public.3gpp public.3gpp2 public.ada-source ... public.camera-raw-image public.case-insensitive-text ... public.fortran-source public.html public.image public.item public.jpeg ...

The UTI mechanism supports multiple inheritance, allowing a UTI to conform to one or more other UTIs. For example, an instance of HTML content is also an instance of textual content. Therefore, the UTI for HTML content (public.html) conforms to the UTI for textual content (public.text). Moreover, textual content is, generically speaking, a stream of bytes. Therefore, public.text conforms to public.data. It also conforms to public.content, which is a UTI describing all content types. The UTTypeConformsTo key is used in a UTI's declaration to specify its conformance to a list of UTIs.

UTIs can be declared in the property list files of application bundles, Spotlight metadata importer bundles, Automator action bundles, and so on. Figure 762 shows an example of a UTI declarationthat of the public.html UTI. A bundle can export a UTI declaration using the UTExportedTypeDeclarations key, making that type available for use by other parties. Conversely, a bundle can import a UTI declaration through the UTImportedTypeDeclarations key, indicating that even though the bundle is not the owner of that type, it wishes to have the type made available on the system. If both imported and exported declarations for a UTI exist, the exported declaration takes precedence.

Figure 762. Example of a UTI declaration

<dict> <!-- one or more UTIs that this UTI conforms to --> <key>UTTypeConformsTo</key> <array> <string>public.text</string> </array> <!-- user-readable string describing this UTI; may be localized --> <key>UTTypeDescription</key> <string>HTML text</string> <!-- the UTI string --> <key>UTTypeIdentifier</key> <string>public.html</string> <!-- icon to use when displaying items of this type --> <key>UTTypeIconFile</key> <string>SomeHTML.icns</string> <!-- the URL of a reference document describing this type --> <key>UTTypeReferenceURL</key> <string>http://www.apple.com</string> <!-- alternate identifier tags that match this type --> <key>UTTypeTagSpecification</key> <dict> <key>com.apple.nspboard-type</key> <string>Apple HTML pasteboard type</string> <key>com.apple.ostype</key> <string>HTML</string> <key>public.filename-extension</key> <array> <string>html</string> <string>htm</string> <string>shtml</string> <string>shtm</string> </array> <key>public.mime-type</key> <string>text/html</string> </dict> </dict>

Note that UTIs do not preclude other tagging methods. In fact, they are compatible with such methods. As shown in Figure 762, content of type HTML text (as specified by the UTTypeDescription key) can be identified by several tags (as specified by the UTTypeTagSpecification key): an NSPasteboard type, a four-character file type code, multiple file extensions, or a MIME type. Therefore, a UTI can unify alternative methods of type identification.

Категории