blob: ea1ebb5dacef97402b48e8abd9b9055c6f10606d [file] [log] [blame] [view]
# ChromeOS HWID Database User Guide
[TOC]
This document is aimed at defining the standard way to update the HWID database.
## Introduction to HWID Database
The role of a hardware ID (HWID) configuration file is to verify that every
hardware component used in a Chrome device is qualified. The config file mainly
lists the phase of the device `image_id`, the pattern of the encoded string
`pattern`, the mapping of bit value to the component `encoded_field`, and the
probe result of each component `component`.
For convenience, we call the HWID config file **HWID database**.
## Update Rule
The HWID database has two tasks: (1) verifies the probe result and generates the
HWID string when building new devices at the factory, and (2) decodes the HWID
string generated by every previous version of the database. To ensure the new
database can successfully decode the old HWID string, there are some rules while
updating the database.
### 1. Common Rule: Only Append, Do Not Modify or Remove Items
The first common rule is: do not remove anything. Because we not only need to
decode current HWID, but also need to decode *EVERY* previous valid HWID. Only
these items can be modified:
- The probeable attribute of the component
- The status of the component item
- The rules items
### 2. Pattern: Do Not Modify the Set of encoded_field {#rule_encoded_field}
It's obvious that we are not allowed to remove the field in the pattern. Adding
a field whose component class is new seems not break the previous HWID, but it
actually causes ambiguity. After adding the component in the pattern, we would
decode old HWID as index = 0. But actually we have no information about this
component in old HWID. There are 3 possible situations:
1. The old device doesn't have the component, so the component is not in the
HWID database.
2. The old device has the component, but it cannot be probed previously.
3. The old device has the component and it can be probed, but user forgot to
add into HWID database.
Most of the case is 1, the old device doesn't have the component. But we don't
enforce index 0, which means there is no probed result (or no component)
currently. So it is weird to allow this happen. The reasonable way is: the
component set in each pattern cannot be modified. It can prevent this ambiguity
from happening.
However, we might lean to relax this rule in the early build. The case (2)
has a high chance of happening: every old device has the component, but it
cannot be probed. Creating a new pattern for adding an extra component seems
overkill. In this case we allow appending the pattern directly.
In summary, if we confirm that all the old device has the same kind of the
component, then it is allowed to append to the current pattern. Otherwise,
please create a new pattern when we need to modify the set of component class.
### 3. Encoded_fields: Do Not Modify Encoded Mapping
Because `encoded_field` is shared with all patterns, the existed items in the
`encoded_field` cannot be modified. Otherwise the old HWID cannot lookup the
correct mapping. Therefore, if we need to change the mapping of a component, we
can only add new field into `encoded_fields`.
### 4. Components: Use deprecated/unsupported to Remove Component
Because the components items should be encoded in `encoded_field` in normal
case, we cannot remove them. When we don't allow a component in the new unit,
use deprecated status. If you don't even allow to match it, use unsupported
status. Please refer [Status of a Component Item](#component_status) for more
details.
## Database Builder
Originally it was tedious to convert the probe result to HWID database. Most of
the time we copy and paste it from an existing project and modify the probe
value. In addition, there are many implicit rules and relations between each
section. For example, the number of bits in the field of the pattern should be
large enough to contain all items in the encoded field.
Now we have a tool called **database builder** to generate or update the HWID
database. This tool is aimed at covering most of the common and tedious HWID
database change, like adding or removing components. But the HWID database still
needs to be manually updated in the following scenarios:
### Scenarios that Cannot Use Database Builder
- **Multiple image_ids are active**
In the database builder, we assume that only the latest (maximum) `image_id`
is active. So we recommend not to use the tool if the assumption is not true.
- **Modify the rules**
The rule section gives us much flexibility in assigning and verifying the
value of the component. On the other hand, there is no universal diagram for
the rule section. We still leave it to user update the rules manually.
- **Change the status of component items**
Because changing the status is quite easy. Just change it :)
### Prerequisites
The command `hwid` must be run on a
[Factory Preflash Image](https://chromium.googlesource.com/chromiumos/platform/factory/+/HEAD/README.md#imaging-methods)
(test image in partition A and release image on partition B) because `hwid`
loads information from other partitions in the factory preflash image. You might
encounter unexpected error if running on the wrong partition.
### Command of Database Builder
```shell
# Views the usage of building a new HWID database.
$ hwid build-database --help
# Views the usage of updating an existing HWID database.
$ hwid update-database --help
```
### Post-Processing
Though the database builder handle most of the work, there is still some
manual post-processing.
- **Check the name of component items**
The builder will decide a name by the probe result, but it might be
meaningless. Please change the name in **encoded_fields** and **components**
if you don't like it.
- **Confirm the status of the component items**
All component items generated by the database builder are **unqualified**.
After the SIE or TAM confirms the component is qualified at AVL, please change
the status to **supported**.
## Use Cases
Below, we will list some common use cases of HWID database change, and provide
the recommendation way to do it.
### 1. Get an initial HWID Database
To update (e.g. add components, change status, etc) the HWID database, we
firstly need to have a HWID database file. To get the initial HWID database
file, please request one from your device management page on ChromeOS Device
Lifecycle Management (DLM). Once the request is accepted, a HWID bundle with
the initial HWID database will be created for you to download.
### 2. Add Probed Value, or Second Source
This is the most common update in HWID database. When we have the initial HWID
DB, we can start to add the probed values, introduce second source, or update
firmware version. We need to add new component item into HWID database. Just
append the new item in the component field and check if the encoding bit is
enough or not. If we update the firmware version, we should mark the old one
as "deprecated" to ensure all DUTs in the factory use the latest firmware.
There are two types of unprobeable components we can use while updating the HWID
DB.
1. (Optional) Check if there are missing components in the probe result. If so,
add a default item with the argument "--add-default-component". Please refer
[Add a Default Item](#add_default_item) for more details.
2. (Optional) Check if there are components that do not exist in some SKU. For
example, one SKU has cellular and another SKU does not. If so, add a null
item with the argument "--add-null-component". Please refer
[Add a Null Item](#add_null_item) for more details.
The command for this scenario is:
```shell
# Get the probe result.
$ hwid collect-material --output-file /tmp/material.yaml
# Update the database at /usr/local/factory/hwid/GOOGLE
$ hwid update-database \
--material-file /tmp/material.yaml \
--project GOOGLE \
--add-default-component battery \
--add-null-component cellular
```
**Note**: Depends on project settings, some components might require
factory device data ready to be probed correctly. Therefore, it's
highly suggested to run `hwid collect-material` on DUT with factory
toolkit ready when preparing the HWID database for on-going
manufacturing builds.
### 3. Add a Default Item {#add_default_item}
When we bring up a device, the probing code for some hardware components might
not be ready. For example, a device cannot probe cellular in EVT build, and can
probe it later. Before the probing code is ready, please add a **default item**.
After the probing code is ready, add the component item and deprecate the
default item.
|||---|||
#### Before updating the HWID config file
```yaml
image_id:
0: EVT
pattern:
- image_ids: [0]
encoding_scheme: base8192
fields: []
encoded_fields: {}
components: {}
```
#### After updating the HWID config file
```yaml
image_id:
0: EVT
pattern:
- image_ids: [0]
encoding_scheme: base8192
fields:
- cellular_field: 3
- other_probeable_component_field: 2
encoded_fields:
cellular_field:
0: {cellular: cellular_default}
other_probeable_component_field:
0: {other_probeable_component: comp_1}
components:
cellular:
items:
cellular_default:
value: NULL
other_probeable_component:
items:
comp_1:
value: {compact_str: aa}
```
|||---|||
The command for this scenario is:
```shell
# While updating the database by the probed result, add a default item with
# "--add-default-component" argument.
$ hwid update-database \
--project GOOGLE \
--add-default-component cellular \
--material-file /tmp/material.yaml # the probe result doesn't contain
# cellulars.
```
### 4. Add a Null Item {#add_null_item}
When we have a special SKU that does not have a component, please add a **null
item**. For example, we have a SKU with cellular component and another SKU
without the cellular component. Then the HWID database should be like:
|||---|||
#### Before adding the null item
```yaml
image_id:
0: EVT
pattern:
- image_ids: [0]
encoding_scheme: base8192
fields:
- cellular_field: 3
encoded_fields:
cellular_field:
0: {cellular: aa}
components:
cellular:
items:
aa:
value: {compact_str: aa}
```
#### After adding the null item
```yaml
image_id:
0: EVT
pattern:
- image_ids: [0]
encoding_scheme: base8192
fields:
- cellular_field: 3
encoded_fields:
cellular_field:
0: {cellular: aa}
1: {cellular: NULL}
components:
cellular:
items:
aa:
value: {compact_str: aa}
```
|||---|||
The command for this scenario is:
```shell
# Add a default item with "--add-null-component" argument.
$ hwid update-database \
--project GOOGLE \
--add-null-component cellular
```
### 5. Deprecate a Component Item
Deprecating the component item is quite easy. Please manually add
"status: deprecated" in the target component item. Then the new unit may not use
this component item.
The example below is to deprecate the cellular component item `aa`.
|||---|||
#### Before deprecating the item
```yaml
image_id:
0: EVT
pattern:
- image_ids: [0]
encoding_scheme: base8192
fields:
- cellular_field: 3
encoded_fields:
cellular_field:
0: {cellular: aa}
1: {cellular: bb}
components:
cellular:
items:
aa:
value: {compact_str: aa}
bb:
value: {compact_str: bb}
```
#### After deprecating the item
```yaml
image_id:
0: EVT
pattern:
- image_ids: [0]
encoding_scheme: base8192
fields:
- cellular_field: 3
encoded_fields:
cellular_field:
0: {cellular: aa}
1: {cellular: bb}
components:
cellular:
items:
aa:
status: deprecated
value: {compact_str: aa}
bb:
value: {compact_str: bb}
```
|||---|||
### 6. Add New Component in Device
When we add new component types during the build, we need to create a new
`pattern` and new `image_id`. Please refer [Update Rule 2](#rule_encoded_field)
for more details.
For example, we don't have cellular in EVT build, but add cellular in DVT build.
To complicate the situation even more, in DVT build we might have one SKU that
has cellular and another SKU that doesn't. In this case, we need to distinguish:
1. No cellular in EVT build
2. No cellular in DVT build
3. Has cellular in DVT build
The difference between 1 and 2 is: in EVT build we don't check the probed result
of the cellular component. The actual meaning should be "we don't have
information about cellular" instead of "this device doesn't have cellular". To
distinguish the case 1 and 2, we need to create a new pattern that adds the new
component, while retaining the old pattern which lacks the component.
The HWID database for this example:
|||---|||
#### Before adding the cellular component
```yaml
image_id:
0: EVT
pattern:
- image_ids: [0]
encoding_scheme: base8192
fields:
- cpu_field: 3
encoded_fields:
cpu_field:
0: {cpu: cpu_aa}
components:
cpu:
items:
cpu_aa:
value: {compact_str: cpu_aa}
```
#### After adding the cellular component
```yaml
image_id:
0: EVT
1: DVT
pattern:
- image_ids: [0]
encoding_scheme: base8192
fields:
- cpu_field: 3
- image_ids: [1]
encoding_scheme: base8192
fields:
- cpu_field: 3
- cellular_field: 3
encoded_fields:
cpu_field:
0: {cpu: cpu_aa}
cellular_field:
0: {cellular: NULL}
1: {cellular: aa}
components:
cpu:
items:
cpu_aa:
value: {compact_str: cpu_aa}
cellular:
items:
aa:
value: {compact_str: aa}
```
|||---|||
The command for this scenario is:
```shell
# Update the database at EVT build
$ hwid update-database \
--project GOOGLE \
--image-id EVT \
--material-file /tmp/material.yaml # the probe result contains doesn't
# contain cellulars.
# Update the database at DVT build.
$ hwid update-database \
--project GOOGLE \
--image-id DVT \
--add-null-component cellular \
--material-file /tmp/material.yaml # the probe result contains the
# cellular "aa".
```
*** note
**Note:** If all the old devices have the same kind of the component, then it is
allowed to append the component in the current pattern.
***
|||---|||
#### Before adding the cellular component
```yaml
image_id:
0: EVT
pattern:
- image_ids: [0]
encoding_scheme: base8192
fields:
- cpu_field: 3
encoded_fields:
cpu_field:
0: {cpu: cpu_aa}
components:
cpu:
items:
cpu_aa:
value: {compact_str: cpu_aa}
```
#### After adding the cellular component
```yaml
image_id:
0: EVT
pattern:
- image_ids: [0]
encoding_scheme: base8192
fields:
- cpu_field: 3
- cellular_field: 3
encoded_fields:
cpu_field:
0: {cpu: cpu_aa}
cellular_field:
0: {cellular: aa}
components:
cpu:
items:
cpu_aa:
value: {compact_str: cpu_aa}
cellular:
items:
aa:
value: {compact_str: aa}
```
|||---|||
The command for this scenario is:
```shell
# Update the database without assigning the image_id.
$ hwid update-database \
--project GOOGLE \
--material-file /tmp/material.yaml # the probe result contains the
# cellular "aa".
WARNING: Extra fields [cellular_field] without assigning a new image_id.
If the fields are added into the current pattern, the index of these fields will
be encoded to index 0 for all old HWID string. Enter "y" if you are sure all old
devices with old HWID string have the component with index 0. [y/N] y
```
Please choose **"Y"** for the question, then the database builder will append
the component into the current pattern.
### 7. Append Full Component Combinations to the Encoded Field
The argument `--fill-combination <ENCODED_FIELD>:<NUMBER_OF_COMPONENTS>`
helps ensure the encoded field contains all possible component combinations.
When a device is equipped with multiple components of the same type (2 cameras,
one for user-facing and one for world-facing, for example), the corresponding
encoded field allocates each unuqie combination a dedicate index number.
Which means that the user will need to register all possible combinations into
the HWID DB. Approaches include running
`hwid updat-database --material-file ...` on all SKUs, or manually appending
all possible combinations based on the build plan. Both of the approaches
involve many manual works, and hence `--fill-combination` is here to simplify
the process.
For example, assuming the HWID DB already includes some existing cameras.
And now we want to add a new camera into HWID DB. The following command
```shell
hwid update-database \
--material-file <COLLECTED_MATERIAL_FILE_FROM_A_DEVICE_WITH_NEW_CAMERA> \
--fill-combination camera_field:2 # Specify to append full combinations of
# 2 components to camera_field.
```
will not only add the new camera into the HWID DB but also make sure
`camera_field` includes all *pairs* of cameras. So if the HWID DB contains
4 cameras in total after update, `camera_fields` will contain at least 10
combinations.
Another usage is that if all the candidate cameras already exist and the user
only want to fulfill the encoded field, they can run the following command,
which will not update the HWID DB based on collected materials and only touch
the specified encoded field.
```shell
hwid update-database \
--skip-update-by-collected-material \
--fill-combination camera_field:2 # Specify to append full combinations of
# 2 components to camera_field.
```
**Note**: Only `unqualified` or `supported` components are used to generate
the combinations.
## Appendix
### Unprobeable Component (Deprecated)
**Deprecation note**: Unprobeable components are no longer allowed in new
HWID configuration files.
When a component with the attribute `probeable: False`, it means one of these:
- The component class is removed at the latest pattern.
- The value is determined at the evaluation time. Set at rule.
- Exception: If there is only one item in this component class, set the index
to 0. It is only for backward compatibility.
**Please use "default" argument instead of using this.**
### Default Component Item
If a component item has a `null` probe values (i.e. `values: null`), or has
the attribute `default: True`, it is a default component item. The feature of
the default component item is:
- It is always matched when generating HWID string, no matter the probe result
exists or not.
- If another component is also matched, then the default component item will be
ignored.
### Status of a Component Item {#component_status}
- **supported**
Default status. The component is currently used to build new units.
- **unqualified**
The component is now allowed to be used after PVT phase. The components added
by the auto-generator should be unqualified. Then SIE or TAM should remove it
after the component is confirmed.
- **deprecated**
The component is no longer being used to build new units, but is supported in
RMA process.
- **unsupported**
The component is not allowed to be used to build new units, and is not
supported in RMA process. The component cannot be matched. It is used for the
wrong component or the equivalent component but with different probed result.
- **duplicate**
The component is a subset of another component, so it should not be matched
while encoding. For example:
```
comp_1:
values:
key: !re 'PART_NUMBER_1-.*'
comp_2:
status: duplicate # this is necessary, otherwise 'PART_NUMBER_1-2' will
# match comp_1 and comp_2, and cause an error.
values:
key: PART_NUMBER_1-2
```
### Internal Only Database Builder Use Cases
The following use cases are **only for Googlers' test purpose**. They are not
applicable for a regular ChromeOS device development journey.
#### 1. Manually Register a Minimal HWID Database for a New Project
**Deprecation note**: This use case is deprecated, please find the minimal
HWID database from the HWID bundle downloaded from ChromeOS Device Lifecycle
Management (DLM) page. For HWID repository owners, please follow project
tracker instructions to create the minimal HWID database on DLM directly.
The steps of generating a minimal HWID database are:
1. Create a minimal DB with the project name and corresponding phase.
```shell
# Create a minimal DB
$ hwid build-database --minimal --project <proj_name> --image-id <initial_phase>
```
an example HWID DB will look like:
```yaml
checksum: <hash>
project: GOOGLE
encoding_patterns:
0: default
image_id:
0: EVT
pattern:
- image_ids:
- 0
encoding_scheme: base8192
fields: []
encoded_fields:
region_field: !region_field []
components:
region: !region_component
rules: []
```
2. Add the project info in `projects.yaml` manifest file.
```yaml
GOOGLE:
board: GOOGLE
branch: main
version: 3
path: v3/GOOGLE
```
3. Submit the change of the two files.
#### 2. Convert Legacy Region Style to List Style
We use magic tag `"!region_field"` to generate the region encoded field. There
are two styles: legacy and list style. In legacy style, each region has its own
index mapping. For example, "us" maps to 29 and "gb" maps to 16. However, in
list style, only the listed regions are encoded. In the example below,
"us" maps to 1 and "gb" maps to 2.
```yaml
encoded_fields:
# Legacy style
old_region_field: !region_field
# List style
new_region_field: !region_field ['us', 'gb']
```
Because the update rule, we cannot just replace the legacy style because the
encoding mapping is different. If we want to convert legacy style to list
style, we should create another `encoded_field` and remove the old one from the
`pattern`. For example:
|||---|||
#### Before converting the style
```yaml
image_id:
0: EVT
pattern:
- image_ids: [0]
encoding_scheme: base8192
fields:
- region_field: 8
encoded_fields:
region_field: !region_field
components:
region: !region_component
```
#### After converting the style
```yaml
image_id:
0: EVT
1: DVT
pattern:
- image_ids: [0]
encoding_scheme: base8192
fields:
- region_field: 8
- image_ids: [1]
encoding_scheme: base8192
fields:
- new_region_field: 5
encoded_fields:
region_field: !region_field
new_region_field: !region_field ['us']
components:
region: !region_component
```
|||---|||
The database builder will automatically convert the style if the old database
uses the legacy style.
*** note
**Note:** a new `image_id` is required when converting.
***