Building Chrome for Chrome OS (Simple Chrome)

This workflow allows you to quickly build/deploy Chromium to any Chromium OS device without needing a Chromium OS source checkout or chroot. It‘s useful for trying out your changes on a real device while you’re doing Chromium development. If you have an OS checkout and want your local Chromium changes to be included when building a full OS image, see the OS development guide.

At its core is the chrome-sdk shell which sets up the shell environment and fetches the necessary SDK components (CrOS toolchain, sysroot, etc.).

Typography conventions

LabelPaths, files, and commands
(outside)on your build machine, outside the chroot
(inside)inside the chrome-sdk shell on your build machine (1)
(device)on your Chromium OS device
(chroot)inside the cros_sdk crhoot

(1) Note: This is not the same thing as the cros_sdk chroot.

Getting started

First make sure you have the following:

  1. Local copy of the Chromium source code and depot_tools. Be certain to update .gclient to include target_os = ["chromeos"].
  2. USB flash drive 4 GB or larger (for example, a Sandisk Extreme USB 3.0)
  3. USB to Gigabit Ethernet adapter

Googlers: Chromestop has the hardware.

Get the Google API keys

In order to sign in to your Chromebook you must have Google API keys:

  • External contributors, see api-keys. You'll need to put them in your out_board/Release/ file, see below.
  • Googlers: see go/building-chrome to get internal source. If you have src-internal in your .gclient file the official API keys will be set up automatically.

Set up gsutil

Use depot_tools/ and run config to set the authentication token. (Googlers: Use your account.) Otherwise steps below may run slowly and fail with “Login Required” from gsutil.

When prompted for a project ID, enter 134157665460 (this is the Chrome OS project ID).

Enter the Simple Chrome environment

Building Chrome for Chrome OS requires a toolchain customized for each Chromebook model (or “board”). Look up your Chromium OS board name by navigating to the URL about:version on the device. For example: Platform 10176.47.0 (Official Build) beta-channel samus has board samus.

To enter the Simple Chrome environment, run this from within your Chromium checkout (not the Chromium OS chroot):

(outside) cd /path/to/chrome/src
(outside) export BOARD=samus  # or your board name
(outside) cros chrome-sdk --board=$BOARD --log-level=info

The command prompt will change to look like (sdk $BOARD $VERSION).

Entering the Simple Chrome environment does the following:

  1. Fetches the Chrome OS toolchain and sysroot (SDK) for building Chrome.
  2. Creates out_$BOARD/Release and generates or updates
  3. Installs and starts Goma. (Non-Googlers may need to disable this with --nogoma).

Non-Googlers: Only generic boards have publicly available SDK downloads, so you will need to use a generic board (e.g. amd64-generic) or your own Chrome OS build (see Using a custom Chromium OS build). For more info and updates star

cros chrome-sdk options:

  • --nogn-gen Do not run ‘gn gen’ automatically.
  • --gn-extra-args='extra_arg=foo other_extra_arg=bar' For setting extra gn args, e.g. ‘dcheck_always_on = true’.
  • --internal Sets up Simple Chrome to build and deploy the official Chrome instead of Chromium.
  • --log-level=info Sets the log level to ‘info’ or ‘debug’ (default is ‘warn’).

Important: When you sync/update your Chromium source, the Chrome OS SDK version (src/chromeos/CHROMEOS_LKGM) may change. When the SDK version changes you may need to exit and re-enter the Simple Chrome environment to successfully build and deploy Chromium.

Note: See also Using a custom Chromium OS build.

Build Chrome

To build Chrome, run:

(inside) autoninja -C out_${SDK_BOARD}/Release chrome chrome_sandbox nacl_helper

Note: Targets other than chrome, chrome_sandbox, nacl_helper, or (optionally) chromiumos_preflight are not supported in Simple Chrome and will likely fail. unit_tests and browser_tests should be run outside the Simple Chrome environment.

Note: Simple Chrome uses Goma. To watch the build progress, find the Goma port ($ echo $SDK_GOMA_PORT) and open http://localhost:<port_number> in a browser.

Note: The default extensions will be installed by the test image you use below.

Set up the Chromium OS device

Before you can deploy your build of Chromium to the device, it needs to have a “test” OS image loaded on it. A test image has tools like rsync that are not part of the end-user image.

Chromium should be deployed to a recent Chromium OS test image, ideally the version shown in your SDK prompt (or (inside) echo $SDK_VERSION).

Create a bootable USB stick

Googlers: Images for all boards are available on go/goldeneye:

  1. Find the matching Chrome OS version and click on the column for ‘Canary’ or ‘Dev’.
  2. Click on the dropdown icon in the ‘Images’ column and click on ‘Unsigned test image’.

Non-Googlers: The build infrastructure is currently in flux. See for more details. You may need to build your own Chromium OS image.

After you download the compressed tarball containing the test image (it should have “test” somewhere in the file name), extract the image by running:

(inside) tar xf ~/Downloads/<image-you-downloaded>

Copy the image to your USB stick using cros flash:

(inside) cros flash usb:// chromiumos_test_image.bin

Tip: If you have a chromiumos checkout, the following can be used to update a device that already has a test image installed. Star for updates on a proposal to support this without a chromiumos checkout.

.../chromeos/src $ cros flash $IP_ADDR chromiumos_test_image.bin

If cros flash does not work you can also create an image using dd. See Flashing an image to USB using dd.

Put your Chrome OS device in dev mode

Note: Switching to dev mode wipes all data from the device (for security reasons).

Most recent devices can use the generic instructions. To summarize:

  1. With the device on, hit Esc + Refresh (F2 or F3) + power button
  2. Wait for the white “recovery screen”
  3. Hit Ctrl-D to switch to developer mode (there's no prompt)
  4. Press enter to confirm
  5. Once it is done, hit Ctrl-D again to boot, then wait

From this point on you'll always see the white screen when you turn on the device. Press Ctrl-D to boot.

Older devices may have device-specific instructions.

Googlers: If the device asks you to “enterprise enroll”, click the X in the top-right of the dialog to skip it. Trying to use your credentials will result in an error.

Enable booting from USB

By default Chromebooks will not boot off a USB stick for security reasons. You need to enable it.

  1. Start the device
  2. Press Ctrl-Alt-F2 to get a terminal. (You can use Ctrl-Alt-F1 to switch back if you need to.)
  3. Login as root (no password yet, there will be one later)
  4. Run enable_dev_usb_boot

Install the test image onto your device

Note: Do not log into this test image with a username and password you care about. The root password is public (“test0000”), so anyone with SSH access could compromise the device. Create a test Gmail account and use that.

  1. Plug the USB stick into the machine and reboot.
  2. At the dev-mode warning screen, press Ctrl-U to boot from the USB stick.
  3. Switch to terminal by pressing Ctrl-Alt-F2
  4. Login as user chronos, password test0000.
  5. Run /usr/sbin/chromeos-install
  6. Wait for it to copy the image
  7. Run poweroff

You can now unplug the USB stick.

Deploying Chrome to the device

To deploy the build to a device, you will need direct SSH access to it from your computer. The scripts below handle everything else.

Connect device to Ethernet

Use your USB-to-Ethernet adapter to connect the device to a network.

Googlers: You can use a corp Ethernet jack, which will place you on a special restricted network.

Checking the IP address

  1. Click the status area in the lower-right corner
  2. Click the network icon
  3. Click the circled i symbol in the lower-right corner
  4. A small window pops up that shows the IP address

You can also run ifconfig from the terminal (Ctrl-Alt-F2).

Using deploy_chrome

The deploy_chrome script uses rsync to incrementally deploy to the device.

Specify the build output directory to deploy from using --build-dir, and the IP address of the target device (which must be ssh-able as user ‘root’) using --to:

(inside) deploy_chrome --build-dir=out_${SDK_BOARD}/Release --to=$IP_ADDR

Note: The first time you run this you will be prompted to remove rootfs verification from the device. This is required to overwrite /opt/google/chrome and will reboot the device. You can skip the prompt with --force.

Deploying Chrome to the user partition

It is also possible to deploy Chrome to the user partition of the device and set up a temporary mount from /opt/google/chrome using the option --mount. This is useful when deploying a binary that will not otherwise fit on the device, e.g.:

  • When using --nostrip to provide symbols for backtraces.
  • When using other compile options that produce a significantly larger image.
(inside) deploy_chrome --build-dir=out_$BOARD/Release --to=$IP_ADDR --mount \

Note: This also prompts to remove rootfs verification so that /etc/chrome_dev.conf can be modified (see Command-line flags and environment variables). You can skip that by adding --noremove-rootfs-verification.

Additional Notes:

  • The mount is transient and does not survive a reboot. The easiest way to reinstate the mount is to run the same deploy_chrome command after reboot. It will only redeploy binaries if there is a change. To verify that the mount is active, run findmnt /opt/google/chrome. The output should be:
TARGET             SOURCE                                      FSTYPE OPTIONS
/opt/google/chrome /dev/sda1[/deploy_rootfs/opt/google/chrome] ext4   rw,nodev,noatime,resgid=20119,commit=600,data=ordered
  • If startup needs to be tested (i.e. before deploy_chrome can be run), a symbolic link will need to be created instead:
    • ssh to device
      • mkdir /home/chrome
      • rm -R /opt/google/chrome
      • ln -s /home/chrome /opt/google/chrome
    • deploy_chrome --build-dir=out_${SDK_BOARD}/Release --to=$IP_ADDR --nostrip
    • The device can then be rebooted and the unstripped version of Chrome will be run.
  • deploy_chrome lives under $CHROME_DIR/src/third_party/chromite/bin. You can run deploy_chrome outside of a chrome-sdk shell.

Updating the Chrome OS image

In order to keep Chrome and Chrome OS in sync, the Chrome OS test image should be updated weekly. See Create a bootable USB stick for a tip on updating an existing test device if you have a chromiumos checkout.


Log files

Chrome-related logs are written to several locations on the device:

  • /var/log/ui/ui.LATEST contains messages written to stderr by Chrome before its log file has been initialized.
  • /var/log/chrome/chrome contains messages logged by Chrome before a user has logged in.
  • /home/chronos/user/log/chrome contains messages logged by Chrome after a user has logged in.
  • /var/log/messages contains messages logged by session_manager (which is responsible for starting Chrome), in addition to kernel messages when a Chrome process crashes.

Command-line flags and environment variables

If you want to tweak the command line of Chrome or its environment, you have to do this on the device itself.

Edit the /etc/chrome_dev.conf (device) file. Instructions on using it are in the file itself.

Custom build directories

This step is only necessary if you run cros chrome-sdk with --nogn-gen.

To create a GN build directory, run the following inside the chrome-sdk shell:

(inside) gn gen out_$SDK_BOARD/Release --args="$GN_ARGS"

This will generate out_$SDK_BOARD/Release/

  • You must specify --args, otherwise your build will not work on the device.
  • You only need to run gn gen once within the same cros chrome-sdk session.
  • However, if you exit the session or sync/update Chrome the $GN_ARGS might change and you need to gn gen again.

You can edit the args with:

(inside) gn args out_$SDK_BOARD/Release

You can replace Release with Debug (or something else) for different configurations. See Debug builds.

GN build configuration discusses various GN build configurations. For more info on GN, run gn help on the command line or read the quick start guide.

Debug builds

For cros chrome-sdk GN configurations, Release is the default. A debug build of Chrome will include useful tools like DCHECK and debug logs like DVLOG. For a Debug configuration, specify --args="$GN_ARGS is_debug=true is_component_build=false" (inside).

Alternately, you can just turn on DCHECKs for a release build. You can do this with --args="$GN_ARGS dcheck_always_on=true".

To deploy a debug build you need to add --nostrip to deploy_chrome because otherwise it will strip symbols even from a debug build. This requires Deploying Chrome to the user partition.

Note: If you just want crash backtraces in the logs you can deploy a release build with --nostrip. You don't need a debug build (but you still need to deploy to a user partition).

Note: You may hit DCHECKs during startup time, or when you login, which eventually may reboot the device. You can check log files in /var/log/chrome or /home/chronos/user/log.

You can create /run/disable_chrome_restart to prevent a restart loop and investigate.

You can temporarily disable these DCHECKs to proceed, but please file a bug for such DCHECK because it's most likely a bug.

Remote GDB

Core dumps are disabled by default. See additional debugging tips for how to enable core files.

On the target machine, open up a port for the gdb server to listen on, and attach the gdb server to the top-level Chrome process.

(device) sudo /sbin/iptables -A INPUT -p tcp --dport 1234 -j ACCEPT
(device) sudo gdbserver --attach :1234 $(pgrep chrome -P $(pgrep session_manager))

On your host machine (inside the chrome-sdk shell), run gdb and start the Python interpreter:

(inside) cd %CHROME_DIR%/src
(inside) gdb out_${SDK_BOARD}/Release/chrome
Reading symbols from /usr/local/google2/chromium2/src/out_link/Release/chrome...
(gdb) pi

Note: These instructions are for targeting an x86_64 device. For now, to target an ARM device, you need to run the cross-compiled gdb from within a chroot.

Then from within the Python interpreter, run these commands:

import os
sysroot = os.environ['SYSROOT']
gdb.execute('set sysroot %s' % sysroot)
gdb.execute('set solib-absolute-prefix %s' % sysroot)
gdb.execute('set debug-file-directory %s/usr/lib/debug' % sysroot)
gdb.execute('set solib-search-path out_%s/Release/lib' % os.environ['SDK_BOARD'])  # Or "Debug" for a debug build
gdb.execute('target remote $IP_ADDR:1234')

If you wish, after you connect, you can Ctrl-D out of the Python shell.

Extra debugging instructions are located at debugging tips.

Additional instructions

Updating the version of the Chrome OS SDK

When you invoke cros chrome-sdk, the script fetches the version of the SDK that corresponds to your Chrome checkout. To update the SDK, sync your Chrome checkout and re-run cros chrome-sdk.


  • Every time that you update Chrome or the Chrome OS SDK, it is possible that Chrome may start depending on new features from a new Chrome OS image. This can cause unexpected problems, so it is important to update your image regularly. Instructions for updating your Chrome OS image are above in Set Up the Chromium OS device.
  • Don't forget to re-configure your custom build directories if you have them (see Custom build directories).

Specifying the version of the Chrome OS SDK to use

You can specify a version of Chrome OS to build against. This is handy for tracking down when a particular bug was introduced.

(outside) cros chrome-sdk --board=$BOARD --version=3680.0.0

Once you are finished testing the old version of the chrome-sdk, you can always start a new shell with the latest version again. Here's an example:

(outside) cros chrome-sdk --board=$BOARD

Updating Chrome

(inside) exit
(outside) git checkout master && git pull   # (or if you prefer, git rebase-update)
(outside) gclient sync
(outside) cros chrome-sdk --board=$BOARD --log-level=info

Tip: If you update Chrome inside the chrome-sdk, you may then be using an SDK that is out of date with the current Chrome. See Updating the version of the Chrome OS SDK section above.

Updating Deployed Files

deploy_chrome determines which files to copy in in the chromite repo which is pulled into chrome/src/third_party/chromite via DEPS.

When updating the list:

  1. Make changes to the appropriate list (e.g. _COPY_PATHS_CHROME).
  2. Be aware that deploy_chrome is used by the chromeos-chrome ebuild, so when adding new files make sure to set optional=True initially.
  3. Changes to chromite will not affect Simple Chrome until a chromite roll occurs.

Using a custom Chromium OS build

If you are making changes to Chromium OS and have a Chromium OS build inside a chroot that you want to build against, run cros chrome-sdk with the --chroot option:

(outside) cros chrome-sdk --board=$BOARD --chroot=/path/to/chromiumos/chroot

Flashing an image to USB using dd

In the below command, the X in sdX is the path to your usb key, and you can use dmesg to figure out the right path (it'll show when you plug it in). Make sure that the USB stick is not mounted before running this. You might have to turn off automounting in your operating system.

(inside) sudo dd if=chromiumos_test_image.bin of=/dev/sdX bs=1G iflag=fullblock oflag=sync

Be careful - you don't want to have dd write over your root partition!

Using cros flash with xbuddy to download images

cros flash with xbuddy will automatically download an image and write it to USB for you. It's very convenient, but for now it requires a full Chrome OS checkout and must be run inside the Chrome OS chroot. (issue 437877)

(chroot) cros flash usb:// xbuddy://remote/$BOARD/<version>/test

Replace $BOARD and <version> with the right values. Both can be seen in your SDK prompt (e.g. (sdk lumpy R27-3789.0.0) is the lumpy board using version R27-3789.0.0).

See the Cros Flash page for more details.

Setting a custom prompt

By default, cros chrome-sdk prepends something like ‘(sdk link R52-8315.0.0)’ to the prompt (with the version of the prebuilt system being used).

If you prefer to colorize the prompt, you can set PS1 in ~/.chromite/chrome_sdk.bashrc, e.g. to prepend a yellow ‘(sdk link 8315.0.0)’ to the prompt:

PS1='\[\033[01;33m\](sdk ${SDK_BOARD} ${SDK_VERSION})\[\033[00m\] \w \[\033[01;36m\]$(__git_ps1 "(%s)")\[\033[00m\] \$ '

NOTE: Currently the release version (e.g. 52) is not available as an environment variable.


The legacy GYP build system is no longer supported.