Cobalt Evergreen is an end-to-end framework for cloud-based deployment of Cobalt updates without the need for supplemental Cobalt integration work on device platforms.
For a bit of background context, as the number of Cobalt devices in the field increases there is a growing proliferation of version fragmentation. Many of these devices are unable to take advantage of the benefits of Cobalt performance, security, and functional improvements as it is costly to integrate and port new versions of Cobalt. We recognized this issue, listened to feedback from the Cobalt community and as a result developed Cobalt Evergreen as a way to make updating Cobalt a much simpler process for everyone involved.
This relies on separating the Starboard(platform) and Cobalt(core) components of a Cobalt implementation into the following discrete components:
Google-built (on Google toolchain)
Partner-built (on Partner toolchain)
libpthread.so
, libEGL.so
)With this new Cobalt platform architecture, less engineering effort is necessary for a full Cobalt integration/deployment. The idea here is you should only need to implement Starboard one time and any Cobalt-level updates should only require platform testing. NOTE that certain new Cobalt features may require Starboard changes, so if you want to take advantage of some of these new features, Starboard changes may be necessary.
loader_app
portionloader_app
component required to be built on platform toolchainsThere are minimal differences in switching to Evergreen as the Cobalt team has already done a majority of the work building the necessary components to support the Evergreen architecture. You will still be responsible for building the Starboard and platform-specific components as usual. Thereafter, switching to Evergreen is as simple as building a different configuration. Please see the Raspberry Pi 2 Evergreen reference port (Instructions) for an example.
Cobalt Evergreen requires that there are two separate build(gyp
) configurations used due to the separation of the Cobalt core(libcobalt.so
) and the platform-specific Starboard layer(loader_app
). As a result, you will have to initiate a separate gyp process for each. This is required since the Cobalt core binary is built with the Google toolchain settings and the platform-specific Starboard layer is built with partner toolchain configurations.
Cobalt Evergreen is built by a separate gyp platform using the Google toolchain:
$ cobalt/build/gyp_cobalt evergreen-arm-softfp-sbversion-12 $ ninja -C out/evergreen-arm-softfp-sbversion-12_qa cobalt
Which produces a shared library libcobalt.so
targeted for specific architecture, ABI and Starboard version.
The gyp variable sb_evergreen
is set to 1 when building libcobalt.so
.
The partner port of Starboard is built with the partner’s toolchain and is linked into the **loader_app
which knows how to dynamically load libcobalt.so
.
cobalt/build/gyp_cobalt <partner_port_name> ninja -C out/<partner_port_name>_qa loader_app
Partners should set sb_evergreen_compatible
to 1 in their gyp platform config. DO NOT set the sb_evergreen
to 1 in your platform-specific configuration as it is used only by Cobalt when building with the Google toolchain.
The following additional Starboard interfaces are necessary to implement for Evergreen:
kSbSystemPathStorageDirectory
kSbMemoryMapProtectExec
#define SB_CAN_MAP_EXECUTABLE_MEMORY 1
configuration_public.h
Only if necessary, create a customized SABI configuration for your architecture. Note, we do not anticipate that you will need to make a new configuration for your platform unless it is not one of our supported architectures:
If your target architecture falls outside the support list above, please reach out to us for guidance.
Some common versions of Cobalt in the field may show a bug in the implementation of the CSS which can cause layout behavior to cause components to overlap and give users a poor user experience. A fix for this is identified and pushed to Cobalt open source ready for integration and deployment on devices.
Though a fix for this was made available in the latest Cobalt open source, affected devices in the field are not getting updated (e.g. due to engineering resources, timing, device end-of-life), users continue to have a poor experience and have negative sentiment against a device. In parallel, the web app team determines a workaround for this particular situation, but the workaround is obtuse and causes app bloat and technical debt from on-going maintenance of workarounds for various Cobalt versions.
The Cobalt team can work with you to guide validation and deployment of a shared Cobalt library to all affected devices much more quickly without all the engineering effort required to deploy a new Cobalt build. With this simpler updating capability, device behavior will be more consistent and there is less technical debt from workarounds on the web application side. Additionally, users can benefit from the latest performance, security, and functional fixes.
Cobalt Evergreen currently supports the following
Target Architectures:
Supported Javascript Engines
Additional reserved storage (96MB) is required for Evergreen binaries. We expect Evergreen implementations to have an initial Cobalt preloaded on the device and an additional reserved space for additional Cobalt update storage.
kSbSystemPathStorageDirectory
As Cobalt Evergreen is intended to be updated from Google Cloud architecture without the need for device FW updates, it is important that this can be done easily and securely on the target platform. There are a set of general minimum requirements to do so:
PROT_WRITE
, PROT_EXEC
) for loading in-memory and performing relocations for Cobalt Evergreen binariesIn order to verify the platform requirements you should run the ‘nplb_evergreen_compat_tests’. These tests ensure that the platform is configured appropriately for Evergreen.
To enable the test, set the sb_evergreen_compatible gyp
variable to 1 in the gyp_configuration.gypi
. For more details please take a look at the Raspberry Pi 2 gyp files.
There is a reference implementation available for Raspberry Pi 2 with instructions available here.
The above diagram is a high-level overview of the components in the Cobalt Evergreen architecture.
Partner-built represents components the Partner is responsible for implementing and building.
Cobalt-built represents components the Cobalt team is responsible for implementing and building.
This is a new component in the Cobalt Shared Library component that is built on top of the Starboard API. The purpose of this module is to check the update servers if there is a new version of the Cobalt Shared Library available for the target device. If a new version is available, the Cobalt updater will download, verify, and install the new package on the target platform. The new package can be used the next time Cobalt is started or it can be forced to update immediately and restart Cobalt as soon as the new package is available and verified on the platform. This behavior will take into account the suspend/resume logic on the target platform.
Functionally, the Cobalt Updater itself runs as a separate thread within the Cobalt process when Cobalt is running. This behavior depends on what the target platform allows.
For more detailed information on Cobalt Updater, please take a look here.
We use Google Update as the infrastructure to manage the Cobalt Evergreen package install and update process. This has been heavily used across Google for quite some time and has the level of reliability required for Cobalt Evergreen. There are also other important features such as:
For more detailed information on Google Update for Cobalt Evergreen, please take a look here.
We use Google Downloads to manage the downloads available for Cobalt Evergreen. The Cobalt Updater will use Google Downloads in order to download available packages onto the target platform. We selected Google Downloads for this purpose due to its ability to scale across billions of devices as well as the flexibility to control download behavior for reliability.
For more detailed information on Google Downloads (Download Server) for Cobalt Evergreen, please take a look here.
The Starboard ABI was introduced to provide a single, consistent method for specifying the Starboard API version and the ABI. This specification ensures that any two binaries, built with the same Starboard ABI and with arbitrary toolchains, are compatible.
Note that Cobalt already provides default SABI files for the following architectures:
You should not need to make a new SABI file for your target platform unless it is not a currently supported architecture. We recommend that you do not make any SABI file changes. If you believe it is necessary to create a new SABI file for your target platform, please reach out to the Cobalt team to advise.
For more detailed information on the Starboard ABI for Cobalt Evergreen, please take a look here.
Cobalt Evergreen provides support for maintaining multiple separate versions of the Cobalt binary on a platform. These versions are stored in installation slots(i.e. known locations on disk), and are used to significantly improve the resilience and reliability of Cobalt updates.
The number of installation slots available will be determined by the platform owner. A minimum of 2 must be available with the limit being the storage available on the platform.
It is worth noting that adding a third installation slot allows a factory image to be permanently installed as a fail-safe option.
The number of installation slots is directly controlled using kMaxNumInstallations
, defined in loader_app.cc.
There are subtle differences between using 2 installation slots and using 3 or more installation slots outlined below.
Both of the installation slots are located in the directory specified by kSbSystemPathStorageDirectory
. This will vary depending on the platform.
On the Raspberry Pi this value will be /home/pi/.cobalt_storage
. The paths to the installation slots will be as follows:
/home/pi/.cobalt_storage/installation_0
(initial installation slot)
/home/pi/.cobalt_storage/installation_1
Where the most recent update is stored will alternate between the two available slots. No factory image is maintained with this configuration so only the two most recent updates will be stored on the machine.
Finally, the installation slot that will be used when Cobalt Evergreen is run would be stored in
/home/pi/.cobalt_storage/installation_store.pb
on the Raspberry Pi.
The 3+ slot configuration is very similar to the 2 slot configuration, but has one major difference: the original installation is maintained, and is stored in a read-only installation slot within the content directory.
On the Raspberry Pi, the installation slots will be as follows:
/home/pi/path-to-cobalt/content/app/cobalt
(initial installation slot) (read-only)
/home/pi/.cobalt_storage/installation_1 /home/pi/.cobalt_storage/installation_2
Similar to the 2 slot configuration, where the most recent update is stored will alternate between the two available slots (not the read-only installation slot).
The installation slot that will be used when Cobalt Evergreen is run is determined, and stored, exactly the same as it is for the 2 slot configuration.
The system font directory kSbSystemPathStorageDirectory
should be configured to point to the standard
(23MB) or the limited
(3.1MB) cobalt font packages. An easy way to do that is to use the loader_app/content
directory and setting the cobalt_font_package
to standard
or limited
in your port.
Cobalt Evergreen, built by Google, will by default use the minimal
cobalt package which is around 16KB to minimize storage requirements. A separate cobalt_font_package
variable is set to minimal
in the Evergreen platform.
On Raspberry Pi this is:
minimal
set of fonts under:
~/.cobalt_storage/installation_0/content/fonts/
standard
or limited
set of fonts under:
loader_app/content/fonts
The ICU table should be deployed under the kSbSystemPathStorageDirectory. This way all Cobalt Evergreen installations would be able to share the same tables. The current storage size for the ICU tables is 7MB.
On Raspberry Pi this is:
/home/pi/.cobalt_storage/icu
The Cobalt Evergreen package will not carry ICU tables by default but may add them in the future if needed. When the package has ICU tables they would be stored under the content location for the installation.
As Cobalt binary packages (CRX format) are downloaded from the Google Downloads server, the verification of the Cobalt update package is critical to the reliability of Cobalt Evergreen. There are mechanisms in place to ensure that the binary is verified and a chain of trust is formed. The Cobalt Updater is responsible for downloading the available Cobalt update package and verifies that the package is authored by Cobalt(and not an imposter), before trying to install the downloaded package.
In the above diagram, the Cobalt Updater downloads the update package if available, and parses the CRX header of the package for verification, before unpacking the whole package. A copy of the Cobalt public key is contained in the CRX header, so the updater retrieves the key and generates the hash of the key coming from the header of the package, say Key hash1.
At the same time, the updater has the hash of the Cobalt public key hard-coded locally, say Key hash2.
The updater compares Key hash1 with Key hash2. If they match, verification succeeds.
Not at this time. All Cobalt updates will be deployed through Google infrastructure. We believe Google hosting the Cobalt core binaries allows us to ensure a high-level of reliability and monitoring in case issues arise.
We expect performance to be similar to a standard non-Evergreen Cobalt port.
Google will work closely with device partners to ensure that the appropriate testing is in place to prevent regressions.
Yes, there are tests available to help validate the implementation:
The Cobalt team is focusing a large amount of effort to identify and integrate various methods to reduce the size of the Cobalt binary such as compression and using less fonts.
Yes, this is one of the benefits of Evergreen. We can initiate an update from the server side that addresses problems that were undetected during full testing. There are a formal set of guidelines to verify an updated binary deployed to the device to ensure that it will work properly with no regressions that partners should follow to ensure that there are no regressions. In addition, it is also critical to do your own testing to exercise platform-specific behavior.
Much of the optimization work remains in the Starboard layer and configuration so you should still expect good performance using Cobalt Evergreen. That being said, the Cobalt Evergreen configuration allows you to customize Cobalt features and settings as before.