Skip to content
This repository has been archived by the owner on Dec 11, 2019. It is now read-only.

How auto updates for Brave work on Windows

dfwdraco76 edited this page Oct 12, 2017 · 5 revisions

TL;DR

The Windows version of Brave uses the open source library Squirrel for keeping itself up-to-date

The much longer version

Creating a package

Here's everything you need to know to start from scratch.

git clone git@github.com:brave/browser-laptop.git
cd browser-laptop
npm install
  • build the package and then build the installer
set CHANNEL=dev
npm run build-package

The package gets put into a folder like .\Brave-win32-x64\. This will contain all the files you need to actually run Brave without having to use npm run watch and npm start. These files are what get put into the installer.

Building the installer

NOTE: you won't be able to build the installer unless you are an employee of Brave Software since it uses an authenticode certificate which must be kept private

set CERT="c:\path-to-cert-here"
set CERT_PASSWORD="authenticode cert password here"
npm run build-installer

Running the above will execute tools/buildInstaller.js which uses the Electron Installer package to build the signed installers. Here's what the code for that looks like:

var electronInstaller = require('electron-winstaller')
var resultPromise = electronInstaller.createWindowsInstaller({
  appDirectory: buildDir,
  outputDirectory: outDir,
  title: 'Brave',
  authors: 'Brave Software',
  loadingGif: 'res/brave_splash_installing.gif',
  setupIcon: 'res/brave_installer.ico',
  iconUrl: 'https://brave.com/favicon.ico',
  signWithParams: format('-a -fd sha256 -f "%s" -p "%s" -t http://timestamp.verisign.com/scripts/timstamp.dll', path.resolve(cert), certPassword),
  exe: 'Brave.exe'
})
resultPromise.then(() => {
  cmds = [
    `mv ${outDir}/Setup.exe ${outDir}/BraveSetup-${arch}.exe`,
    `mv ${outDir}/Setup.msi ${outDir}/BraveSetup-${arch}.msi`
  ]
  execute(cmds, {}, console.log.bind(null, 'done'))
}, (e) => console.log(`No dice: ${e.message}`))

At the end of this snippet, you'll have an EXE and MSI installer.

What happens when the installer is being built?

It's important to note that behind the scenes, the electronInstaller object is configuring a nuget package which includes Squirrel. The file which contains the important stuff is called template.nuspectemplate and looks like this:

<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
  <metadata>
    <id><%- name %></id>
    <title><%- title %></title>
    <version><%- version %></version>
    <authors><%- authors %></authors>
    <owners><%- owners %></owners>
    <iconUrl><%- iconUrl %></iconUrl>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description><%- description %></description>
    <copyright><%- copyright %></copyright>
  </metadata>
  <files>
    <file src="locales\**" target="lib\net45\locales" />
    <file src="resources\**" target="lib\net45\resources" />
    <file src="*.bin" target="lib\net45" />
    <file src="*.dll" target="lib\net45" />
    <file src="*.pak" target="lib\net45" />
    <file src="*.txt" target="lib\net45" />
    <file src="Update.exe" target="lib\net45\squirrel.exe" />
    <file src="icudtl.dat" target="lib\net45\icudtl.dat" />
    <file src="LICENSE" target="lib\net45\LICENSE" />
    <file src="LICENSES.chromium.html" target="lib\net45\LICENSES.chromium.html" />
    <file src="<%- exe %>" target="lib\net45\<%- exe %>" />
  </files>
</package>

These fields get filled out by the code in the electronInstaller object. There are a few important fields under the files section:

  • Update.exe: this is key to how Squirrel gets used. Instead of launching into your executable, you launch into this Squirrel executable which can check for updates. Launching this will get you to the most recent version of the product.
  • <%- exe %>: this gets filled in when the installer is being created and in our case would be Brave.exe.

Where does this get installed to?

There are two key locations to remember:

  • %USERPROFILE%\AppData\Local\brave: this is where the binaries get installed to
  • %APPDATA%\brave: this is where the SESSION data gets installed to

The binaries are in a directory structure like this:

  • %USERPROFILE%\AppData\Local\brave
    • app-0.12.13
      • Brave.exe
      • all other files created in the packaging process
    • app-0.12.14
      • Brave.exe
      • all other files created in the packaging process
    • packages
      • temp files; for example the nupkg file, the RELEASE file, etc.
    • app.ico
    • SquirrelSetup.log (contains lots of great info for troubleshooting! these are the logs from when the install or upgrade takes place)
    • Update.exe (our entry point into Brave)
    • Update.VisualElementsManifest.xml

With the exception of a log file, nothing in the SESSION directory is touched by Squirrel. Here are some files that are included there:

  • %APPDATA%\brave
    • session-store-1 (contains all your bookmarks, current windows, most recently closed windows, preferences and really important settings. See our docs to learn more)
    • updateLog.log (contains logs captured when updates were checked during program execution)
    • ledger-* (files used for Brave Payments)

How does Brave know to update itself?

There is a file called Updater.js which has the logic to check for updates and (when ready) to quit / install / re-launch Brave. This wraps the electron.autoUpdater functionality exposed by electron and is used in app/index.js. The important parts of this file you'll want to see (just search for these):

  • checkForUpdate
  • autoUpdater.on('update-downloaded'
  • quitAndInstall

What happens when an update is available?

When the above (Updater.js) finds an update, it'll ask the user if they want to restart with the latest update. At this point, it's put the downloaded content into the %USERPROFILE%\AppData\Local\brave\packages folder.

If the user says "Yes", Brave will immediately dump it's state and quit the program. It's important to note that the quitAndInstall method gets called in Electron, which starts the next part of the process.

The actual upgrade

This is where the new directory gets created with the contents of the nupkg. Squirrel then updates any shortcuts that exist with the new location (since it has moved). It's VERY important to note that for this to work, we have to call setAppUserModelId. This basically ties all the shortcuts together using the app ID set by Squirrel. In our case, this is com.squirrel.brave.Brave.

During the install / upgrade process, logs will be updated showing what was updated (notice that multiple shortcuts are updated auto-magically!):

2016-12-07 13:21:41> ApplyReleasesImpl: Writing files to app directory: C:\Users\brian\AppData\Local\brave\app-0.12.13
2016-12-07 13:21:45> ApplyReleasesImpl: Squirrel Enabled Apps: [C:\Users\brian\AppData\Local\brave\app-0.12.13\Brave.exe,C:\Users\brian\AppData\Local\brave\app-0.12.13\Brave_ExecutionStub.exe]
2016-12-07 13:21:47> ApplyReleasesImpl: Processing shortcut 'C:\Users\brian\AppData\Roaming\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar\Brave.lnk'
2016-12-07 13:21:47> ApplyReleasesImpl: Old shortcut target: 'C:\Users\brian\AppData\Local\brave\Update.exe'
2016-12-07 13:21:47> ApplyReleasesImpl: New shortcut target: 'C:\Users\brian\AppData\Local\brave\Update.exe'
2016-12-07 13:21:47> ApplyReleasesImpl: Old iconPath is: 'C:\Users\brian\AppData\Local\brave\app-0.12.13\Brave.exe'
2016-12-07 13:21:47> ApplyReleasesImpl: Setting iconPath to: 'C:\Users\brian\AppData\Local\brave\app-0.12.13\Brave.exe'

Can we hook into install/upgrade events?

Why yes, we can. We have a script specifically for doing that. This makes use of a Brave owned fork of Electron Squirrel Startup. A good example of where we needed this logic is used is to execute braveDefaults.exe which is used so that Windows sees our application as an HTTP/HTTPS handler.

This would be the place we want to investigate resetting the default browser setting (which is lost during the upgrade). For more info, see https://github.com/brave/browser-laptop/issues/5246