sparkle

Leopard adoption passes 50%

According to numbers sent in by Sparkle, Leopard usage among people using my software has just passed 50%, just over 7 weeks after Leopard's release. The most recent numbers show 51.9% on 10.5 (49.7% on 10.5.1 and the rest still inexplicably sticking with 10.5). The plot below also shows a solid 40% sticking with 10.4.11 for now.

I'm waiting to see what sudden changes might occur after Christmas, or possibly after MacWorld next month. Either could mean a lot of new Macs replacing or supplementing old ones.

The latest numbers from Sparkle can always be found on the Sparkle Stats page, which is automatically updated every night.

Framework Signing Update

I recently wrote about problems using Leopard code signing with Mac OS X frameworks. I've since gotten feedback on my bug report. It looks like the problem isn't so much that frameworks can't be signed but that the correct signing procedure isn't documented.

The code signing documentation indicates that bundles should be signed. Frameworks are bundles, so if you're looking to sign your code you'll likely be tempted to sign a framework like this:

$ codesign -s "authority info" Sparkle.framework

But if you do that you run into the confusing situation I encountered, with your framework structure modified and difficulty knowing if the bundle is valid or not.

The feedback I got on my bug report explains that code signing should be done differently for versioned bundles like frameworks and... whatever other versioned bundles there might be. Although frameworks commonly contain only one version, they're designed so that multiple versions can be present. When signing a framework then, you sign the specific version, not the entire framework bundle. So instead of the above, you instead do something like this:

$ codesign -s "authority info" Sparkle.framework/Versions/A

If there are other versions, sign them separately.

This leaves the framework structure unmodified:

$ find Sparkle.framework/ -name Sparkle -exec ls -l {} \;
lrwxr-xr-x  1 tph  wheel  24 Nov 29 11:44 Sparkle.framework/
    /Sparkle -> Versions/Current/Sparkle
-rwxr-xr-x  1 tph  wheel  242928 Nov 29 11:44 Sparkle.framework/
    /Versions/A/Sparkle

Of course when verifying the signature, you also need to verify the versions independently of the framework bundle. The framework itself won't have a valid signature, but that's not what you should be looking at anyway:

$ codesign -vvv Sparkle.framework/Versions/A
Sparkle.framework/Versions/A: valid on disk
$ codesign -vvv Sparkle.framework/
Sparkle.framework/: code or signature modified

This seems to make sense. A framework is designed to allow multiple independent bundles, with symbolic links to indicate which is current. So, sign each bundle on its own.


Don't Sign that Framework

Yesterday I was working on a forthcoming update to Chimey and I noticed something odd. Chimey of course makes use of SparklePlus for automatic updates, and after a test run of my build-for-release script, Sparkle was looking a little odd.

Normally a framework has one or more binaries, with a symbolic link pointing to the current version. From the command line you'd expect something like this:

$ find Sparkle.framework/ -name Sparkle -exec ls -l {} \;
lrwxr-xr-x  1 tph  wheel  24 Nov 21 11:20 Sparkle.framework/
    /Sparkle -> Versions/Current/Sparkle
-rwxr-xr-x  1 tph  wheel  233088 Nov 21 11:20 Sparkle.framework/
    /Versions/A/Sparkle

Instead I was seeing this:

find Sparkle.framework/ -name Sparkle -exec ls -l {} \;
-rwxr-xr-x  1 tph  wheel  242928 Nov 21 11:20 Sparkle.framework/
    /Sparkle
-rwxr-xr-x  1 tph  wheel  233088 Nov 21 11:20 Sparkle.framework/
    /Versions/A/Sparkle

Yow, how the hell did that happen? I thought it might have something to do with copying the framework, either when compiling or when building the disk image, but that wouldn't account for the different file sizes. A quick check on the current version of Chimey showed that this was something new, not something I'd been doing all along without realizing it.

So what was different? My build-for-release script now signs my code using Leopard code signing.

Apple's documentation on code signing indicates that "You should sign every program in your product, including applications, tools, hidden helper tools, utilities and so forth." Chimey's main bundle includes a preference pane and two helper tools, so I was making sure to sign all of them. The main documentation doesn't mention frameworks specifically, but the Code Signing Release notes indicate that "You may also sign any libraries, frameworks, plugins, and scripts you ship, whether they are delivered with an application or separately." Framework signatures don't get checked yet but might be in the future. I had made my script as future-proof as possible by signing the Sparkle framework now.

But if you sign a framework, the codesign tool modifies the structure of the framework, as I found with Sparkle. Just for sanity's sake I made sure that this affects any Mac OS X framework and is not some kind of Sparkle-specific behavior.

And the file sizes? I can guess what's going on, but I made sure:

$ codesign -vvv Sparkle.framework/Sparkle 
Sparkle.framework/Sparkle: valid on disk
$ codesign -vvv Sparkle.framework/Versions/A/Sparkle
Sparkle.framework/Versions/A/Sparkle: code object is not signed

Not only is codesign changing the framework structure, it's also leaving the framework in an inconsistent state with regard to whether it's signed. Instead of one binary I've got two, and even though I signed the framework, one of those two is still unsigned.

At the same time, checking on the framework bundle still returns a valid signature, despite the presence of unsigned code in there:

$ codesign -vvv Sparkle.framework
Sparkle.framework: valid on disk

It's a good thing that Leopard doesn't currently check on framework signatures. For now it seems it's probably best not to bother signing a framework. Although codesign leaves you with something that should work, it's not clear that it's actually doing anything useful, and it's bloating the framework size in the process.

This has been filed as bug #5609522 with Apple, in case anyone from Apple reads this.


Daily SparklePlus Stats Updates

Last week I posted my first public SparklePlus data. Starting today, SparklePlus charts can be found on my Sparkle Stats page, updated nightly.

I've improved the charting system over the past couple of days to provide more detail than the charts in my previous blog post. Instead of just gathering up each week's data into a single value, the new plots include daily totals for the previous 60 days. Each day's numbers are a running average of the previous seven days, to smooth out daily variations into more comprehensible trends. I'm not sure that a seven-day running total is the best window, so I may experiment with longer or shorter windows and see what happens.

As of today Leopard has reached 45.6% of users, not quite a majority yet but closing in fast.

First public SparklePlus data

Update: SparklePlus charts can now be found on my Sparkle Stats page, updated nightly.

Last year when I was getting MondoMouse ready for release, one of the things I really wanted was an automatic-update system, so that the software could locate and optionally install new versions of itself. Though I try to make as much noise as possible over new releases, people often don't know about them. And even if they do, downloading and installing by hand can be a pain if there are a lot of updates.

Enter Sparkle, a Cocoa framework designed to do exactly that with a minimum of effort.

But that wasn't all I wanted to add. One chronic problem for developers is figuring out what versions of the operating system needed continued support, and which could be dropped. If I don't know if any of my users are still on, say, 10.3, how do I know if I need to continue supporting it? I don't want to waste time with it if nobody's using it, but at the same time I don't want to accidentally strand a huge number of users because my gut feeling turned out to be wrong.

Basically I needed something like the OmniGroup's statistics page. That would mean having MondoMouse-- with the user's permission, of course-- periodically send my server some anonymous information about their Mac, including what version of Mac OS X they're using. Since Sparkle would already be contacting my server on a regular schedule to check for updates, it seemed the ideal solution was to send this information along at the same time.

So I modified Sparkle and created SparklePlus. It did the same thing as Sparkle but with the addition of this anonymous information about people's Macs.

In the spirit of being as open as possible about the process, I always intended to make this information publicly available. But getting that set up was harder than it seemed and became easy to put off.

Until today. Here's some of what I've been collecting.

MondoMouse users are adopting Leopard at a surprisingly fast pace. Just a couple of weeks after release, 45% of MondoMouse users have upgraded:

The Intel/PowerPC ratio has been surprisingly stable though:

Same goes for the number of CPU cores on people's Macs, though it's interesting that nearly 80% have at least two:

There are a number of other details collected, but I haven't been able to develop useful plots of them all yet. For example SparklePlus reports how much RAM is installed, but there are too many different values to show them all and so far my plot-generation script can't coalesce values into ranges.

My plan is to set up a special page for this information, and have the charts updated on a weekly basis. That should be coming soon.


Atomic Bird, LLC