Google Omaha Tutorial

Google Omaha is the open-source version of Google Update, the technology which keeps desktop apps such as Chrome up to date. Integrating Omaha into fman was difficult, so we wrote this tutorial to make it easier for others.

How Chrome's auto-update mechanism works

When you install Chrome, you are actually running a binary built with Omaha. This binary contacts Google's servers and asks what the latest version of Chrome is. The server responds with the URL of a .exe file that can be used to install Chrome. Omaha downloads this file and runs it. It also displays a simple GUI with progress information:

Omaha installer

The .exe which was downloaded by Omaha installs Chrome into C:\Program Files (x86)\Google\Chrome. It also creates registry keys at HKLM\Software\Wow6432Node\Google\Update\Clients:

Omaha registry keys

If you're wondering about Program Files (x86) and Wow6432Node, that's because Omaha is still a 32-bit application, probably for maximum compatibility with existing systems. (What's also interesting is that even 64-bit Chrome is installed into Program Files (x86) and not Program Files.)

The registry keys in the screenshot are a vital point of communication between Omaha and the applications it manages. Each application that wants to be kept up to date by Omaha needs to have a registry key under Software\​Wow6432Node\​Google\​Update\​Clients. Chrome is registered there under the globally constant id {8A69D345-D564-463c-AFF1-A69D9E530F96}. You can see in the screenshot that its version is 52.0.2743.116. Another interesting id is {430FD4D0-...}. This is the key Omaha uses to update itself! ;-)

Omaha also sets up two tasks in the Windows Task Scheduler:

Omaha registry keys

You sometimes see them as GoogleUpdate.exe in the Task Manager:

Omaha registry keys

When the update tasks run, Omaha looks at the registry keys shown above to see which applications need to be updated, and what versions they are at. It sends this information to the update server. When a new version is available, the server responds with the URL of an .exe file which can be used to update the respective application.

A nice feature of this .exe-based approach is that Omaha and the update server are completely agnostic of the applications they manage. The only thing the two components need are executables which perform the application-specific update/installation steps.

Another important feature of Omaha is that it handles permission issues. For example, Chrome may be installed with an administrator account, but then run under a normal user account without permissions to perform updates. Omaha performs all update and installation tasks with the same privileges as the original installation. This for instance allows a non-privileged user to "check for updates" in a system-wide installation.

Using Omaha in your own projects

Omaha is open source. To use it in your own projects, you need to modify its source code, install the necessary tools to compile it, and set up a server to host your updates. This process typically takes you one week.

If you want to save time setting up Omaha, we offer to do it for you. When you fill in the form below, we send you your custom-branded copy of Omaha and login details to a server for rolling out your updates.

This service is free for 30 days. After this period, if you want to continue using our servers, we will kindly ask that you pay a monthly fee. Alternatively, you can also obtain the source code of your custom-branded version of Omaha from us for USD/EUR 199. This lets you use your own (self-hosted) update servers instead.

Appears in installer messages such as "Your Product was installed".

Names the update executable (eg. MyCompanyUpdate.exe). Appears in messages such as "MyCompany update failed."

The website of your company or product, eg. mycompany.com.

Where we'll send the binaries.

The rest of the tutorial assumes that you have an update server and Omaha binaries that fetch updates from this server.

Build an installer

As explained above, Omaha always receives .exe files in response to install/update requests. For instance, the client says "I would like to install app XYZ." and the server answers "You can do this with https://.../install.exe." Likewise for updates: The client says "I have version 1.0 of XYZ, is there an update?" and the server responds "Yes, there's 1.1. You can use https://.../update.exe to update." We will now build the most basic installer.exe. We use Go for this task but you may also use other technologies such as NSIS (as long as your installer supports "silent installation").

Please install Go if you don't already have it. Then create a file install.go with the following contents:

package main

import "golang.org/x/sys/windows/registry"

func check(e error) {
    if e != nil {
        panic(e)
    }
}

func main() {
    const company = `Company`
    const product = `Product`
    const productId = `{9B01C5D1-7F78-4A4E-A89B-0415F6466BC7}`
    const version = `0.0.1.0`

    regKey := `SOFTWARE\` + company + `\Update\Clients\` + productId
    k, _, err := registry.CreateKey(registry.LOCAL_MACHINE, regKey, registry.WRITE | registry.WOW64_32KEY)
    check(err)
    defer k.Close()
    check(k.SetStringValue("pv", version))
    check(k.SetStringValue("name", product))
}

You need to set company, product and productId in the snippet to match your values:

  • If you received Omaha from us then we sent you the values to use.
  • If you prepared Omaha yourself and didn't change the registry key at which it looks for updates, then you need to use Google for the company. Otherwise, use whatever you picked instead of "Google" in the registry paths. Unless you built a tagged meta installer, it's likely that you did not specify your product and productId. If that's the case, please pick these values now. product is your product's name (eg. Chrome). productId is simply a GUID. You can use the one from the snippet, but it's probably better to generate a new one.

Assuming Go is on your PATH, you should be able to build install.go after cding into the directory containing it:

set GOPATH=%cd%
go get golang.org/x/sys/windows/registry
go build install.go

When you run the generated install.exe, a new registry key should be created at HKLM\​SOFTWARE\​Wow6432Node\​Company\​Update\​Clients\​{GUID}.

You may wonder why we are creating this strange registry key. The reason is that if installer.exe doesn't create this key, then Omaha believes that the installation failed. The registry is a crucial point of contact between your app and Omaha!

Upload the installer to the server

Log in to /admin on the update server. Click on Omaha/Applications on the left-hand side. Add an application with ID the same value as the productId above and name the value from product. Do include the curly braces {} in the ID.

Click on Versions on the left. Add a version for your app, in the stable channel, with number the same as version in the install script. Upload install.exe from the previous step as the file. Click "Add another Action" at the bottom. Select install as Event and enter install.exe into Run. Click Save.

Install your app with Omaha!

We can now use Omaha to install our very basic app. Before we do this however, we want to clean up any remainders of a previous installation:

  1. Delete the registry key HKLM\SOFTWARE\Wow6432Node\Company\Update.
  2. Delete the directory C:\Program Files (x86)\Company\ (if it exists).

In both steps please replace Company by the corresponding value from your fork of Omaha.

Your fork of Omaha should have produced an analogue to GoogleUpdate.exe, possibly named after your company instead of Google. If you built Omaha yourself then it should lie in omaha\scons-out\dbg-win\staging. Execute it on a command line, with the following parameters:

CompanyUpdate.exe /install "bundlename=Product&appguid={9B01C5D1-7F78-4A4E-A89B-0415F6466BC7}&appname=Product&needsadmin=True&lang=en"

(Replace the company, product name and ID by your own values.) If all goes well, you should see a standard installer GUI, eventually notifying you that the installation was successful:

Omaha install complete

At this point, you may want to check that the registry at HKLM\​SOFTWARE\​Wow6432Node\​Company\​Update\​Clients\​{GUID} was again created. If not, please see Troubleshooting below.

Troubleshooting

If the installation with Omaha was unsuccessful, then it may help to turn on logging in Omaha. You can do this by creating the file C:\CompanyUpdate.ini (replace Company as usual) with the following contents:

[LoggingLevel]
LC_CORE=5
LC_NET=4
LC_PLUGIN=3
LC_SERVICE=3
LC_SETUP=3
LC_SHELL=3
LC_UTIL=3

LC_OPT=3
LC_REPORT=3

[LoggingSettings]
EnableLogging=1
LogFilePath="C:\foo\OmahaUpdate.log"
MaxLogFileSize=10000000

ShowTime=1
LogToFile=1
AppendToFile=1
LogToStdOut=0
LogToOutputDebug=1

[DebugSettings]
SkipServerReport=1
NoSendDumpToServer=1
NoSendStackToServer=1

This snippet is from Omaha's documentation. It works if you are running a debug build of Omaha. It produces c:\foo\OmahaUpdate.log, which you can inspect for any glaring error messages. What may also be enlightening is to search for <request / <response in the log and compare this with the protocol specification.

Update your app

Now that your app is "installed", it's time to create an update. Replace the version in install.go by a higher value, eg. 0.0.2.0. Compile install.go as before. Log into the update server's admin interface, and create a new Version for your app there (ensure you use the version number from install.go). Upload the newly generated install.exe. Click Add another Action at the bottom. This time however, select update as event. Enter install.exe into Run. Click Save.

To force an update check, delete the registry key HKLM\​Software\​Wow6432Node\​Company\​Update\​LastChecked. Open the Windows Task Scheduler and run the task CompanyUpdate...UA by right-clicking. You should now see CompanyUpdate.exe in the list of running processes in the Windows Task Manager. Once it has disappeared from the list, the registry key at HKLM\​SOFTWARE\​Wow6432Node\​Company\​Update\​Clients\​{GUID}\pv should have been updated to the new version. This means that your update was successfully applied. Congratulations! You have successfully completed this tutorial. If you have any questions or comments, we would love to hear from you. Please don't hesitate to get in touch.

Further considerations

Now that you have completed the tutorial, you will want to apply your knowledge to create a real-world installer for your own app. Here are some tips for issues you will likely encounter.

Tagged Meta Installer

To install our app in the tutorial, we had to execute the complicated command line CompanyUpdate.exe /install .... You obviously don't want your users to have to type this. Omaha addresses this issue via Tagged Meta Installers. These are .exes which wrap CompanyUpdate.exe with hard-coded command line arguments (/install ....) so the user can simply double-click the file. If you obtained Omaha from us, then we also supplied you with such an installer. Otherwise, you need to create it yourself following the instructions in the link just mentioned.

Code signing

Windows executables need to be signed or your users may get ugly warnings:

Windows SmartScreen

In particular, Omaha needs to be built with a code signing certificate if you want to make sure such warnings are not shown. When you obtain Omaha from us, we assist you with this (or do it for you). Otherwise, you need to supply the --authenticode_file and --authenticode_password parameters to Omaha's build.

Packaging files with Go

Our Go-based installer in the tutorial only created some registry keys. But a real-life installer will also need to package and extract some files. One way of doing this in Go is via go-bindata. This library allows packaging arbitrary files inside a Go-built binary.

User/machine installations

Throughout this tutorial, we have performed machine installations, meaning that Omaha's binaries were installed in C:\Program Files (x86) and registry keys were created under HKEY_LOCAL_MACHINE. Omaha also supports user installations. These install apps for the current user only, in C:\​Users\​%user%\​AppData\​Local, and create registry keys under HKEY_CURRENT_USER. You will likely want to support both kinds of installation. The following very simplistic Go function can be used in your installer to determine if a user- or machine install is being performed:

func isUserInstall() bool {
    return strings.HasPrefix(os.Args[0], os.Getenv("LOCALAPPDATA"))
}

Command line arguments

The update server currently only allows uploading one .exe per Version. This .exe needs to be able to both perform a clean install as well as an update from a previous version of an app. To tell the installer whether to install or to update, you can use command-line arguments. When you add the Version in the admin menu, supply two Actions, one for Event install and one for Event update, with different Arguments (eg. -install and -update). You can parse these arguments in Go to determine which action to perform.

Directory structure

Omaha's update task may run at any time, in particular while an instance of your app is running. When an update needs to be performed, you usually cannot simply overwrite your app's files while it is running. To address this issue, we recommend creating a separate directory for each version of your application:

  • C:\Program Files (x86)\Company\YourApp\
    • app.exe looks at available versions and launches the latest one.
    • 1.0.0.0\
    • 2.0.0.0\
      • app.exe <- latest version

When performing an update, you can then simply create a new subdirectory (eg. 3.0.0.0) for the new version without disturbing any running instances of your app.