| # Chromium Updater Developer's Manual |
| |
| This manual provides information on how to develop the |
| [Chromium Updater](https://source.chromium.org/chromium/chromium/src/+/main:chrome/updater/), |
| including tips and tricks. |
| |
| [TOC] |
| |
| ## Code Organization |
| |
| ## Bots & Lab |
| |
| >**_NOTE:_** Knowledge in this section may become out-of-date as LUCI evolves |
| quickly. |
| |
| ### Builders / Testers |
| There are two sets of configuration files for our builders/testers. One is |
| for chromium-branded and locates in `src`. The other one is for chrome-branded |
| and locates in `src-internal`. |
| |
| #### Chromium-branded (`src`) |
| - Console: https://ci.chromium.org/p/chromium/g/chromium.updater/console |
| - `tools/mb/mb_config.pyl`: specifies GN args. |
| - `testing/buildbot/gn_isolate_map.pyl`: maps a GN label to GN targets, and |
| provides test arguments, for example test timeout values. |
| - `testing/buildbot/test_suites.pyl`: maps test suite name to GN label, and |
| provides optional swarming dimensions. |
| - `testing/buildbot/waterfalls.pyl`: maps tester to test suites names, and |
| specifies OS, architecture etc. |
| - `infra/config/subprojects/chromium/ci/chromium.updater.star`: defines our |
| testers and builders and how they appear on the console. |
| |
| Command to update json files after configure update: |
| - `tools\mb\mb train` (if `mb_config.pyl` is changed). |
| - `lucicfg generate .\infra\config\main.star` (if `chromium.updater.star` |
| is changed). |
| - `vpython3 .\testing\buildbot\generate_buildbot_json.py` |
| |
| Reference CLs: |
| - Add a tester: https://crrev.com/c/4068601 |
| - Update GN args: https://crrev.com/c/3656357 |
| |
| #### Chrome-branded (`src-internal`) |
| - Console: https://ci.chromium.org/p/chrome/g/chrome.updater/console |
| - `tools/mb/mb_config.pyl`: specifies GN args. |
| - `testing/buildbot/gn_isolate_map.pyl`: maps a GN label to GN targets, and |
| provides test arguments, for example test timeout values. |
| - `testing/buildbot/test_suites.pyl`: maps test suite name to GN label, and |
| provides optional swarming dimensions. |
| - `testing/buildbot/waterfalls.pyl`: maps tester to test suites names, and |
| specifies OS, architecture etc. |
| - `infra/config/subprojects/chrome/ci/chrome.updater.star`: defines our |
| testers and builders and how they appear on the console. |
| |
| Command to update json files after configure update: |
| - `..\src\tools\mb\mb train -f tools\mb\mb_config.pyl` (if `mb_config.pyl` |
| is changed). |
| - `lucicfg generate .\infra\config\main.star` (if `chrome.updater.star` |
| is changed). |
| - `vpython3 .\testing\buildbot\generate_testing_json.py` |
| |
| Please note changes in `src-internal` needs to roll into chromium/src to take |
| effect. This could take hours until a CL authored by |
| `chromium-internal-autoroll@` lands. During transition, the configure files |
| could be in inconsistent state and leads to infra error. |
| |
| ### Run tests on swarming |
| `mb` tool can upload your private build target (and all the dependencies, |
| based on build rule) to swarming server and run the target on bots. The |
| upload may take quite some time if the target changed a lot since the last |
| upload and/or your network is slow. |
| |
| * Simple scenario: |
| |
| ``` |
| .\tools\mb\mb.bat run -v --swarmed .\out\Default updater_tests -- --gtest_filter=*Integration* |
| ``` |
| |
| * Sometimes the mb tool may fail to match the testing OS (when doing |
| cross-compile) or you may want to run the task on certain kind of bots. |
| This can be done by specifying bots dimension with switch `-d`. Remember |
| `--no-default-dimensions` is necessary to avoid dimension value conflict. |
| Example: |
| |
| ``` |
| .\tools\mb\mb.bat run --swarmed --no-default-dimensions -d pool chromium.win.uac -d os Windows-10 .\out\Default updater_tests_system -- --gtest_filter=*Install* |
| ``` |
| |
| * `mb` can schedule tests in the pools managed by different swarming servers. |
| The default server is |
| [chromium-swarm.appspot.com](https://chromium-swarm.appspot.com/botlist?k=pool). |
| To schedule tests to pools managed by |
| [chrome-swarming.appspot.com](https://chrome-swarming.appspot.com/botlist?k=pool), |
| for example `chrome.tests`, add `--internal` flag in the command line: |
| |
| ``` |
| tools/mb/mb run -v --swarmed --internal --no-default-dimensions -d pool chrome.tests -d os Windows-10 out/WinDefault updater_tests |
| ``` |
| |
| * If `mb` command failed with error `isolate: original error: interactive login is required`, you need to login: |
| |
| ``` |
| tools/luci-go/isolate login |
| ``` |
| |
| * If your test introduces dependency on a new app on macOS, you need to let |
| `mb` tool know so it can correctly figure out the dependency. Example: |
| https://crrev.com/c/3470143. |
| |
| * To run tests on `Arm64`, the mb tool needs to be invoked as follows: |
| |
| ``` |
| .\tools\mb\mb run -v --swarmed --no-default-dimensions --internal -d pool chrome.tests.arm64 out\Default updater_tests_system -- --gtest_filter=LegacyAppCommandWebImplTest.FailedToLaunchStatus |
| ``` |
| |
| * When system tests crash, the stack is missing from the swarming log. This can be avoided if you suppress the test bot mode: |
| |
| ``` |
| .\tools\mb\mb run -v --swarmed --no-bot-mode out\Default updater_tests_system |
| ``` |
| |
| ### Accessing Bots |
| TODO(crbug.com/40841197): Document how to remote into bots for debugging. |
| |
| ### Updating the Checked-In Version of the Updater |
| An older version of the updater is checked in under `//third_party/updater/*/cipd`. |
| This version of the updater is used in some integration tests. The updater is |
| pulled from |
| [CIPD](https://chrome-infra-packages.appspot.com/p/chromium/third_party/updater) |
| based on the versions specified in `//DEPS`. A system called `3pp` periodically |
| updates the packages in CIPD, based on a combination of the Chromium build |
| output and what is actually released through Omaha servers. The configuration |
| for 3pp can be found in `//third_party/updater/*/3pp`. |
| |
| To update these copies of the updaters: |
| 1. Land whatever CLs need to be committed on trunk. |
| 2. Wait for builds to be available in CIPD that have the needed changes. |
| * Instead of waiting, you can instead modify the `fetch.py` scripts for |
| 3pp. For Chrome builds, make sure the build has been released in Omaha |
| then update the fetch script with the desired version number. For |
| Chromium, make sure the build exists in GCS (the |
| chromium-browser-snapshots bucket), then update the min version in the |
| script. The min version usually is different per-platform, since |
| Chromium does not archive a version at every CL. After making these |
| changes, 3pp will import the new versions within a few hours. |
| * As an example, let us suppose that |
| [revision 1371769](https://crrev.com/1371769) |
| is the change that needs to be picked up for the checked-in version. |
| * Look up the chrome version by checking |
| [chromiumdash](https://chromiumdash.appspot.com/). |
| * It shows that version `132.0.6791.0` is the version `1371769` was |
| released with. |
| * Make sure the `updater` is shipping at a `version` higher than |
| `132.0.6791.0` |
| [here](https://versionhistory.googleapis.com/v1/chromium_updater/platforms/win/channels/canary/versions/all/releases?filter=endtime=none) |
| . |
| * Look up the chromium versions under |
| [commondatastorage](https://commondatastorage.googleapis.com/chromium-browser-snapshots/index.html) |
| , in the folders corresponding to `get_platform()` for each |
| `fetch.py`, for instance, the `Win`, `Win_x64`, and `Win_Arm64` |
| folders for the Windows `fetch.py` files, and look up a build with a |
| revision greater than `1371781`, corresponding to `r1371769`, and make |
| sure that the `updater.zip` file is present in those folders. |
| * Make changes to the `fetch.py` files based on the lookups, and send it |
| out for review. |
| * After the change lands, give it a few hours for the fetch to complete. |
| 3. Update //DEPS to point to the new versions. |
| |
| ## Developing |
| ### Cross-platform Code |
| Where possible, cross-platform code is preferred to other alternatives. This |
| means that the source code of the updater is organized in sub-directories, |
| first by functionality (or feature), and second by platform name. For example, |
| the source code contains `updater\net` instead of `updater\mac\net`. |
| |
| ### Strings and file paths |
| |
| Strings in `Posix` are 8-bit encoded characters, usually (but not always) using |
| `UTF8` encoding. |
| |
| Strings in `Windows` can be 8-bit or 16-bit characters, usually `UTF8` or |
| `UTF16` respectively. The `updater` project uses 16-bit strings for most |
| Windows-specific literals, since that is the Chromium coding style for Windows, |
| and there are some Windows APIs that only have the `W` variant that require |
| 16-bit strings. |
| |
| The `updater` project uses 8-bit literals and 8-bit characters for |
| cross-platform code, and uses conversion functions such as `base::UTF8ToWide` |
| and `base::WideToUTF8` to convert to and from 8-bit strings for Windows-specific |
| code paths that are called from the cross-platform code. |
| |
| Using the `ASCII` functions is not allowed in the `updater` codebase, unless |
| there is no alternative native or `UTF8` function. |
| |
| #### Appending strings to a file path |
| |
| When appending strings to a `FilePath`, there are several functions available, |
| such as: |
| * `Append`: appends a string using the native format |
| * `AppendUTF8`: appends a UTF8-encoded string |
| * `AppendASCII`: appends an ASCII-encoded string. ASCII is a subset of UTF8. |
| This function is not used in the `updater` project. |
| |
| These are the rules to follow when appending strings to a `FilePath`: |
| |
| 1. Use `base::FilePath::Append` for platform-specific code |
| * Since `Append` does not do any conversions, it is the safest function to |
| use for platform-specific code, since the characters can retain their |
| native format without undergoing any conversions. |
| 2. Use `base::FilePath::Append` for cross-platform code where |
| `FILE_PATH_LITERAL` can be used to wrap the literals |
| * Since `Append` does not do any conversions, it is the most efficient |
| function to use in this case. |
| 3. Use `base::FilePath::AppendUTF8` for all other cross-platform code |
| * cross-platform code is expected to use UTF8 literals or UTF8 strings |
| only. |
| |
| #### Creating a file path from a string |
| |
| These are the rules to follow when constructing a `FilePath` from a string: |
| |
| 1. Use the `base::FilePath` constructor for platform-specific code |
| * Since the `base::FilePath` constructor does not do any conversions, it |
| is the safest function to use for platform-specific code, since the |
| characters can retain their native format without undergoing any |
| conversions. |
| 2. Use the `base::FilePath` constructor for cross-platform code where |
| `FILE_PATH_LITERAL` can be used to wrap the literals |
| * Since the `base::FilePath` constructor does not do any conversions, it |
| is the most efficient function to use in this case. |
| 3. Use `base::FilePath::FromUTF8Unsafe` for all other cross-platform code |
| * cross-platform code is expected to use UTF8 literals or UTF8 strings |
| only. |
| |
| #### Converting a file path to a string |
| |
| These are the rules to follow when converting a `FilePath` to a string: |
| |
| 1. Use `base::FilePath::value()` for platform-specific code |
| * Since `value()` does not do any conversions, it is the safest function |
| to use for platform-specific code, since the characters can retain their |
| native format without undergoing any conversions. |
| 2. Use `base::FilePath::AsUTF8Unsafe` for cross-platform code |
| * `AsUTF8Unsafe` is safe to use for both `Posix` (where it returns the |
| underlying string unmodified) and `Windows` (where the underlying wide |
| string is converted using `base::WideToUTF8`). |
| |
| ### Mind the dependencies |
| |
| To enforce layering, there are enforced rules about what can be included in |
| certain modules. The rules checked by `GN` and the build breaks on bots if the |
| dependencies constraints are not satisfied. |
| |
| Use the following command to check the target dependencies: |
| `gn check out\Default chrome/updater:* --check-generated --check-system` |
| |
| ## Building |
| |
| ### Configuring the build |
| |
| After creating your build configuration directory via |
| [`gn gen`](https://chromium.googlesource.com/chromium/src/+/main/docs/linux/build_instructions.md#Setting-up-the-build) |
| (this step is equivalent across all platforms), you will need to use |
| [`gn args`](https://www.chromium.org/developers/gn-build-configuration/) to |
| configure the build appropriately. |
| |
| #### Flags required for building successfully |
| |
| As of 2023-05-24, the updater cannot be built in component mode. It is also not |
| specifically designed to be built without the updater being enabled. You must |
| specify these options to `gn` via `gn args`: |
| |
| ``` |
| is_component_build=false |
| enable_updater=true |
| ``` |
| |
| Depending on other configuration options, the default `symbol_level`, 2, might |
| produce object files too large for the linker to handle (in debug builds). |
| Partial symbols, via `symbol_level=1`, fix this. Omitting almost all symbols |
| via `symbol_level=0` reuslts in a smaller and faster build but makes debugging |
| nearly impossible (call stacks will not be symbolicated). |
| |
| #### Faster builds |
| |
| Reclient is a distributed compiler service that allows you to compile Chromium |
| fast. The necessary Reclient binaries are distributed via CIPD and |
| automatically installed when you run gclient sync. After you've |
| set up Reclient, specify it in `gn args` with `use_remoteexec=true`. |
| |
| To get started on Reclient, and for more information on how to use it, see |
| [macOS build instructions](https://chromium.googlesource.com/chromium/src/+/main/docs/mac_build_instructions.md), |
| [Windows build instructions](https://chromium.googlesource.com/chromium/src/+/main/docs/windows_build_instructions.md), |
| or [Google-internal documentation](go/building-chrome), if you are a Google |
| employee. |
| |
| #### More release-like builds |
| |
| Chromium projects build in debug mode by default. Release builds (also called |
| "opt", or "optimized", builds) are faster to link and run more efficiently; |
| they are, of course, much harder to debug. For a release build, add the |
| following to the build configuration's `gn args`: |
| |
| ``` |
| is_debug=false |
| ``` |
| |
| With a Google `src-internal` checkout, you can create a Chrome-branded build: |
| |
| ``` |
| is_chrome_branded=true |
| include_branded_entitlements=false |
| ``` |
| |
| Updater branding affects the path the updater installs itself to, among other |
| things. Differently-branded copies of Chromium Updater are intended to coexist |
| on a machine, operating independently from each other. |
| |
| ### Build output |
| The build generates the following main files: |
| |
| - `updater.exe` (Windows) / `ChromiumUpdater.app` (macOS): The actual updater |
| application. |
| - `UpdaterSetup.exe` (Windows): The self-extracting "metainstaller", suitable |
| for tagging, signing, and further distribution. |
| - `UpdaterSigning`: A collection of scripts and tools used to sign the |
| updater. |
| - `qualification_app` (.exe on Windows): A simple app run by each version of |
| the updater prior to taking over as the active updater. Updaters will |
| download and run whatever version is actually released (not what you've |
| built), and the qualification app can be version skewed with the updater. |
| - `ChromiumUpdaterUtil` (macOS): A utility program for debugging the updater. |
| - `chrome/updater/.install` (macOS): A Keystone-compatible install script that |
| drives the updater's installation during update. |
| - `updater.zip`: A zip file containing all of the above, for uploading to the |
| archive / signing infrastructure. |
| |
| ### Cleaning the build output |
| Running `ninja` with `t clean` cleans the build out directory. For example: |
| ``` |
| ninja -C out\Default chrome/updater:all -t clean |
| ``` |
| |
| ### How to generate the cross-compilation IDL COM headers and TLB files |
| |
| 6 different build flavors need to be built in sequence. If you see errors |
| similar to the following: |
| ``` |
| midl.exe output different from files in gen/chrome/updater/app/server/win, see C:\src\temp\tmppbfwi0ds |
| To rebaseline: |
| copy /y C:\src\temp\tmppbfwi0ds\* c:\src\chromium\src\third_party\win_build_output\midl\chrome\updater\app\server\win\x64 |
| ninja: build stopped: subcommand failed. |
| ``` |
| |
| You can then run the following command to update IDL COM files for all flavors: |
| ``` |
| python3 tools/win/update_idl.py |
| ``` |
| |
| ### Build artifacts |
| |
| Build outputs will land in the directory created by `gn gen` that you have been |
| providing to assorted `gn`, `ninja`, and `autoninja` commands. `updater.zip` |
| contains copies of the "final" outputs created by the build. `UpdaterSetup` is |
| probably what you want for installing the updater you have built. |
| |
| ## Signing |
| |
| GoogleUpdater signing doesn't take place on Chromium infra, but rather on |
| proprietary Google infrastructure (go/o4signing). The build system packages all |
| necessary ingredients for signing in updater.zip, which is uploaded by Chrome |
| archive builders to the unsigned builds bucket in GCS. The zip contains both |
| the artifacts to be signed and scripts to sign them. Signing infrastructure is |
| triggered after each upload, ingests the files, injects the key material, signs, |
| and then uploads the results to the signed builds bucket. More detail is |
| available for Googlers at go/o4signing. |
| |
| On Windows, it's important to sign updater.exe, and then package that into |
| UpdaterSetup.exe, and sign UpdaterSetup.exe. The signing scripts take an |
| unsigned UpdaterSetup.exe, extract updater.exe, sign, reconstruct, and then |
| sign the new UpdaterSetup.exe. |
| |
| On macOS, the GoogleUpdater.app bundle is signed directly, and then notarized |
| (sent to Apple for countersigning). Notarization is "stapled" into the app |
| bundle, and then the entire thing is packaged into a DMG, which in turn is |
| signed, notarized, and stapled. |
| |
| ## Code Coverage |
| Gerrit now down-votes the changes that do not have enough coverage. And it's |
| nice to have good coverage regardless. To improve code-coverage, we need to |
| know what are already covered and what are not. |
| |
| #### Coverage on Gerrit |
| It's automatically generated. But the coverage shown is the combined result |
| from all OS platforms. |
| |
| #### Coverage Dashboard |
| The [updater code coverage dashboard](https://analysis.chromium.org/coverage/p/chromium/dir?host=chromium.googlesource.com&project=chromium/src&ref=refs/heads/main&path=//chrome/updater/&platform=mac) |
| supports breakdown by OS platform or test type. But it is only for the code in |
| trunk. |
| |
| #### Run Coverage Locally |
| We can quickly get OS-specific coverage result with the local changes: |
| |
| * macOS/Linux |
| ``` |
| gn gen out/coverage --args="use_clang_coverage=true is_component_build=false is_chrome_branded=true is_debug=true use_debug_fission=true use_remoteexec=true symbol_level=2" |
| |
| vpython3 tools/code_coverage/coverage.py updater_tests -b out/coverage -o out/report -c 'out/coverage/updater_tests' -f chrome/updater |
| ``` |
| |
| * Windows |
| ``` |
| gn gen out\coverage --args="use_clang_coverage=true is_component_build=false is_chrome_branded=true is_debug=true use_debug_fission=true use_remoteexec=true symbol_level=2" |
| |
| vpython3 tools\code_coverage\coverage.py updater_tests -b out\coverage -o out\report -c out\coverage\updater_tests.exe -f chrome/updater |
| ``` |
| The last command outputs an HTML file and you can open it in browser to see the |
| coverages. |
| |
| |
| ## Unit tests and integration tests |
| ### Running tests locally |
| |
| The updater tests are available as `updater_tests` build target in the `out` |
| directory of the build. |
| |
| In general, running branded unit tests locally is likely to break the updater |
| for the browser. To avoid this outcome when unsuspecting developers build and |
| run the branded updater tests, the test don't run locally unless the |
| developer sets an environment variable `ISOLATED_OUTDIR`. This is an |
| environment variable which is present on all bots (see the updater logs |
| section below). The presence of `ISOLATED_OUTDIR` does not preserve the |
| updater though. It only prevents the tests from being run. |
| |
| |
| ## Debugging |
| ### Debug into Windows update service |
| |
| * Install updater: ```UpdaterSetup.exe --install [--system]``` |
| > **_TIP:_** Debugger may have trouble to find the symbols at the service |
| side even if you add your build output directory to the symbol paths. To |
| workaournd the issue, you can copy `updater.exe*` to the versioned |
| installation directory. |
| * Set a breakpoint at the client side after service instantiation but before |
| calling into the service API. Most likely this will be somewhere in file |
| `update_service_proxy.*`. |
| * Start the client, wait for it to hit the break point. At this time, the |
| service process should have started. |
| * Find the server process, which contains the command line switch `--server` |
| (user-level server) or `--system --windows-service` (system-level server). |
| Start another debugger and attach the server process. Then set a server-side |
| breakpoint at the place you want to debug. |
| * Continue the client process. |
| |
| ### Logging |
| |
| Both the updater and the unit tests can create program logs. |
| |
| #### Updater logs |
| |
| The updater itself logs in the product directory. |
| |
| #### Unit test logs |
| |
| The unit tests log into a directory defined by the environment variable |
| `${ISOLATED_OUTDIR}`. When run by Swarming, the updater logs are copied |
| into `${ISOLATED_OUTDIR}` too, so that after the swarming task has completed, |
| both types of logs are available as CAS outputs. The logs for |
| `updater_tests_system` and `integration_test_helper` are merged into |
| `updater_tests_system.log`. |
| |
| Non-bot systems can set up this environment variable to collect logs for |
| debugging when the tests are run locally. |
| |
| ## Testing src changes with trybots |
| |
| In some cases, you will want to test the changes you make within |
| [chromium/src](https://chromium.googlesource.com/chromium/src.git) on |
| specific builders/testers before landing these changes. It is possible |
| to do this with the use of the trybots available on the |
| [tryserver.chromium.updater](https://ci.chromium.org/ui/p/chromium/g/tryserver.chromium.updater/builders) |
| waterfall. The steps are as follows: |
| |
| 1. Find a trybot to run your tests with. All of the trybots on the |
| tryserver.chromium.updater waterfall have a corresponding builder and |
| tester, so find one that runs a workflow to test your changes. |
| 2. Apply your configuration changes to chromium/src and upload a CL |
| using the typical workflow: `git cl upload` |
| 3. Run `git cl try -B luci.chromium.try -b {TRYBOT_NAME}` with the |
| name of the trybot you found. |
| 4. Monitor and debug any failures as you normally would for any |
| builder or tester. |
| |
| ### UI Strings & Localization |
| The strings for the metainstaller live in the //chrome/app/chromium_strings.grd |
| and //chrome/app/google_chrome_strings.grd files. This allows the updater |
| strings to utilize the Chromium repo's translation process instead of generating |
| its own. Having it in existing grd files also eliminates the need to onboard |
| updater specific grd files. |
| |
| During the build process, the updater strings are embedded directly into the |
| metainstaller binary via `generate_embedded_i18n`. `generate_embedded_i18n` also |
| allows an `extractor_datafile`, which can define specific strings to pick out |
| from the originating grd file. This way, the metainstaller only has the strings |
| specific to the updater and not any of the other strings within the grd file. |
| When the `generate_embedded_i18n` is complete, it generates an |
| `updater_installer_strings.h` header, which contains macro definitions of the |
| message ids and the offsets. The strings are mapped with their var name appended |
| with `_BASE`. Then the `_BASE` appended macros are defined to be the first |
| localization id in the list, in which case it is `_AF`. |
| |
| An example from the `updater_installer_strings.h` |
| ``` |
| #define IDS_BUNDLE_INSTALLED_SUCCESSFULLY_AF 1600 |
| #define IDS_BUNDLE_INSTALLED_SUCCESSFULLY_AM 1601 |
| |
| ... |
| |
| #define IDS_BUNDLE_INSTALLED_SUCCESSFULLY_BASE IDS_BUNDLE_INSTALLED_SUCCESSFULLY_AF |
| |
| ... |
| |
| #define DO_STRING_MAPPING \ |
| HANDLE_STRING(IDS_BUNDLE_INSTALLED_SUCCESSFULLY_BASE, IDS_BUNDLE_INSTALLED_SUCCESSFULLY) \ |
| ``` |
| |
| Within the metainstaller, an l10_util.h/cc has three functions to get localized |
| strings. |
| ``` |
| GetLocalizedString(int base_message_id) |
| GetLocalizedStringF(int base_message_id, const std::wstring& replacement) |
| GetLocalizedStringF(int base_message_id, std::vector<std::wstring> replacements) |
| ``` |
| |
| One function for getting the literal string and two functions to get formatted |
| strings. `GetLocalizedString()` uses the base id plus the offset based on the |
| language to look through the binary's string table to get the correct, localized |
| string. The formatted strings utilize GetLocalizedString() to get the string and |
| then uses `base::ReplaceStringPlaceholders()` to remove the `$i` placeholders |
| within the string. With regards to picking the correct language to utilize for |
| the localized string, `base::win::i18n::GetUserPreferredUILanguageList()` is |
| used to get the preferred UI languages from MUI. If there are multiple languages |
| in the list, the first language in the list is picked. |
| |
| #### Steps to add a new UI String to the updater |
| |
| * Add the string to chrome/app/chromium_strings.grd and |
| chrome/app/google_chrome_strings.grd. For example: |
| ``` |
| <message name="IDS_NO_NETWORK_PRESENT_ERROR" |
| desc="Error message displayed in the main dialog when the Updater is unable to connect to the network."> |
| Unable to connect to the Internet. If you use a firewall, please allowlist <ph name="PRODUCT_EXE_NAME">$1<ex>ChromiumUpdater.exe</ex></ph>. |
| </message> |
| ``` |
| * Add the identifier for the string, for example `IDS_NO_NETWORK_PRESENT_ERROR`, |
| in chrome/updater/win/ui/resources/create_metainstaller_string_rc.py. |
| * Use the string identifier in the code. For example: |
| ``` |
| GetLocalizedStringF(IDS_NO_NETWORK_PRESENT_ERROR_BASE, L"updater.exe"); |
| ``` |
| * Add tests for the new string in the UI if applicable. |
| * Capture a screenshot of the UI with the new string. |
| * Save the screenshot as chrome\app\chromium_strings_grd\IDS_NO_NETWORK_PRESENT_ERROR.png |
| and chrome\app\google_chrome_strings_grd\IDS_NO_NETWORK_PRESENT_ERROR.png. |
| * Run `python3 tools/translation/upload_screenshots.py` |
| * This will generate chrome\app\chromium_strings_grd\IDS_NO_NETWORK_PRESENT_ERROR.png.sha1 |
| and chrome\app\google_chrome_strings_grd\IDS_NO_NETWORK_PRESENT_ERROR.png.sha1. |
| * Add these `.sha1` files to your CL. Do not add the actual `.png` images to |
| your CL. |
| * Once the images are successfully uploaded via `upload_screenshots.py`, delete |
| them from your local enlistment. |
| |
| However, if `upload_screenshots.py` encounters the following error, then the |
| screenshots have to be manually uploaded to |
| https://storage.cloud.google.com/chromium-translation-screenshots/. |
| |
| ``` |
| ServiceException: 401 Anonymous caller does not have storage.objects.list |
| access to the Google Cloud Storage bucket. Permission 'storage.objects.list' |
| denied on resource (or it may not exist). |
| ``` |
| |
| To manually upload each screenshot: |
| * Get the `sha1` generated from the tool. So for example, for |
| chrome/app/chromium_strings_grd/IDS_UNKNOWN_APPLICATION.png, the `sha1` is |
| `085c88707d854787e0c1310d93b519e93d906592`. |
| * Rename the `.png` file to the `sha1` hash name. So for example, rename |
| `chrome/app/chromium_strings_grd/IDS_UNKNOWN_APPLICATION.png` to |
| `chrome/app/chromium_strings_grd/085c88707d854787e0c1310d93b519e93d906592`. |
| * upload |
| `chrome/app/chromium_strings_grd/085c88707d854787e0c1310d93b519e93d906592` to |
| https://storage.cloud.google.com/chromium-translation-screenshots/. |
| * Edit the `content-type` from `application/octet-stream` to `image/png`. |
| |
| ## Troubleshooting |
| |
| ### Build errors |
| |
| * **Maybe it's not you.** If you pulled from `origin/main` since your last |
| successful build, or have never successfully built on your current branch, |
| and the build errors you're seeing aren't obviously related to any changes |
| you've made, |
| [check the tree status](https://chromium-status.appspot.com/status_viewer). |
| Did you pull down a broken version? If so, and the revert is in, pull again |
| and see if it works better. Or skip checking the tree status and just try |
| this as your first debugging step for build breaks after a pull. |
| * **Dependencies are a fast-moving target.** Remember to run `gclient sync -D` |
| after every pull from `origin/main` _and_ every branch change. If you aren't |
| sure whether you ran it, just run it, it's fast if you don't need it. |
| * **Symbols too big?** If your build is failing during linking, check your |
| `gn args` to verify that `symbol_level=1` (or `0`) is present. If it's not, |
| you're running into a known issue where the default symbol level, `2`, |
| outputs symbols too large for the linker to comprehend. |
| |
| ### Interpreting numeric exit codes and error codes |
| |
| * Chrome installer exit codes: early in |
| [chrome/installer/util/util_constants.h](https://chromium.googlesource.com/chromium/src/+/main/chrome/installer/util/util_constants.h) |
| * Updater installer and update service errors: as of 2025-08-15, they start at |
| line 327 of |
| [chrome/updater/constants.h](https://chromium.googlesource.com/chromium/src/+/main/chrome/updater/constants.h) |
| * Update client errors: |
| [components/update_client/update_client_errors.h](https://chromium.googlesource.com/chromium/src/+/main/components/update_client/update_client_errors.h) |
| * Response codes reported from the network fetcher are standard HTTP |
| response codes. |
| * Update service state and result codes in general: |
| [chrome/updater/mojom/updater_service.mojom](https://chromium.googlesource.com/chromium/src/+/main/chrome/updater/mojom/updater_service.mojom) |
| which are intended to stay in sync with the equivalent enumerations in |
| [chrome/updater/update_service.h](https://chromium.googlesource.com/chromium/src/+/main/chrome/updater/update_service.h) |
| * Chromium Mini-Installer exit codes: |
| [chrome/installer/mini_installer/exit_code.h](https://chromium.googlesource.com/chromium/src/+/main/chrome/installer/mini_installer/exit_code.h) |
| * LZMA unpacker error codes: |
| [chrome/installer/util/lzma_util.h](https://chromium.googlesource.com/chromium/src/+/main/chrome/installer/util/lzma_util.h) |