Bastian Kersting | 18c9e72 | 2022-08-17 09:11:11 | [diff] [blame] | 1 | # Telemetry Extension API |
| 2 | |
| 3 | This document describes the Architecture for the third-party Telemetry |
| 4 | Extensions Platform. |
| 5 | |
| 6 | [TOC] |
| 7 | |
| 8 | # Overview |
| 9 | |
| 10 | The Telemetry Extension Platform provides means for accessing Telemetry and |
| 11 | Diagnostics data of a ChromeOS device. The Telemetry Extension Platform |
| 12 | consists of 2 parts: |
| 13 | |
| 14 | 1. A Chrome headless extension for API access, background data gathering and |
| 15 | processing (Telemetry Extension) |
| 16 | |
| 17 | 2. A companion [Progressive Web App (PWA)](https://web.dev/progressive-web-apps/) |
| 18 | to show UI to a user. |
| 19 | |
| 20 | The Telemetry Extension uses |
| 21 | [Manifest V3](https://developer.chrome.com/docs/extensions/mv3/intro/) to |
| 22 | benefit from using |
| 23 | [Service Workers](https://developer.chrome.com/docs/workbox/service-worker-overview/) |
| 24 | instead of a background script. Only when the PWA is open, the Telemetry |
| 25 | Extension periodically receives user driven requests from the PWA to fetch |
| 26 | telemetry and run diagnostics routines. The PWA also has its own launch icon |
| 27 | and it doesn’t have direct access to the telemetry and diagnostics API, but it |
| 28 | communicates with the Telemetry Extension using message passing. |
| 29 | |
| 30 | This image shows an overview of the architecture. |
| 31 | <br> |
| 32 | <br> |
Bastian Kersting | 43c4f525 | 2022-08-18 12:47:06 | [diff] [blame] | 33 |  |
Bastian Kersting | 18c9e72 | 2022-08-17 09:11:11 | [diff] [blame] | 34 | |
| 35 | # Components |
| 36 | |
| 37 | ## Telemetry Extension |
| 38 | |
| 39 | The Telemetry Extension's role is to handle requests from the UI and gather |
| 40 | telemetry and diagnostics data. The Telemetry Extension has a service worker |
| 41 | and does not have a launch icon. For this specific situation a new Chrome |
| 42 | extension type was declared, the ChromeOS System extension. In a ChromeOS |
| 43 | System extension, the service worker has direct access to normal |
| 44 | [web APIs](https://developer.mozilla.org/en-US/docs/Web/API). Most of the |
| 45 | [common Chrome Extension APIs](https://developer.chrome.com/docs/extensions/reference/) |
| 46 | are disabled (besides `chrome.runtime` to communicate with the PWA) and access |
| 47 | to the Telemetry API is granted either directly through `os.` or via DPSL.js |
| 48 | the recommended way of using the API). Please note that each extension ID needs |
| 49 | to be allowlisted by Google in the Chrome codebase to have access to APIs. |
| 50 | |
| 51 | ## PWA |
| 52 | |
| 53 | It is the role of the PWA to show UI to the user and communicate with the |
| 54 | Telemetry Extension to get telemetry and diagnostics data. The PWA has a |
| 55 | launch icon, UI, and access to web APIs. |
| 56 | |
| 57 | ## DPSL.js |
| 58 | |
| 59 | DPSL.js stands for Diagnostic Processor Support Library for Javascript, it’s a |
| 60 | JS wrapper around the underlying Telemetry Extensions APIs. It offers an |
| 61 | abstracted way for querying the API and is supported and updated by Google to |
| 62 | always support the latest APIs. DPSL.js is Google’s recommended way to interact |
| 63 | with the telemetry extension APIs. The library is hosted on |
| 64 | [Github](https://github.com/GoogleChromeLabs/telemetry-support-extension-for-chromeos) |
| 65 | and published to [npm](https://www.npmjs.com/package/cros-dpsl-js), please refer |
| 66 | to the documentation. |
| 67 | [These tables](https://github.com/GoogleChromeLabs/telemetry-support-extension-for-chromeos/tree/main/src#functions) |
| 68 | show an overview of all available API functions. |
| 69 | |
| 70 | ## Communication |
| 71 | |
| 72 | A Chrome extension and a PWA can communicate with each other using message |
| 73 | passing. Only PWAs can initiate communication because a PWA is running only |
| 74 | when the user launches it. |
| 75 | The following example shows how the communication between the two components |
| 76 | could look like. The PWA uses `chrome.runtime.sendMessage` to communicate with |
| 77 | the Chrome extension: |
| 78 | |
| 79 | ```javascript |
| 80 | // PWA code |
| 81 | |
| 82 | // The ID of the extension we want to talk to. |
| 83 | var editorExtensionId = "abcdefghijklmnoabcdefhijklmnoabc"; |
| 84 | |
| 85 | // Make a simple request: |
| 86 | chrome.runtime.sendMessage( |
| 87 | /* extensionId */ editorExtensionId, |
| 88 | /* message in JSON */ {openUrlInEditor: url}, |
| 89 | /* callback */ function(response) { |
| 90 | if (!response.success) |
| 91 | handleError(url); |
| 92 | }); |
| 93 | ``` |
| 94 | |
| 95 | The extension side can handle incoming requests as follows: |
| 96 | |
| 97 | ```javascript |
| 98 | // Extension code |
| 99 | |
| 100 | chrome.runtime.onMessageExternal.addListener( |
| 101 | function(request, sender, sendResponse) { |
| 102 | if (sender.url == blocklistedWebsite) |
| 103 | return; // don't allow this web page access |
| 104 | if (request.openUrlInEditor) |
| 105 | openUrl(request.openUrlInEditor); |
| 106 | }); |
| 107 | ``` |
| 108 | |
Bastian Kersting | db7db9f | 2022-11-30 17:29:00 | [diff] [blame] | 109 | [//]: <> (This section is part of the API terms of use, internal version is) |
| 110 | [//]: <> (here go/telemetry-extension-tos. DO NOT EDIT unless changes in source) |
| 111 | ## Permission to API Functionality Mapping |
| 112 | |
| 113 | For an overview of all exposed function under `chrome.os.telemetry` and |
| 114 | `chrome.os.diagnostics`, please visit |
| 115 | [this page](https://github.com/GoogleChromeLabs/telemetry-support-extension-for-chromeos/blob/main/src/README.md#functions). |
| 116 | Some telemetry data requires special permissions to be accessed: |
| 117 | |
| 118 | 1. `VpdInfo.serialNumber` requires additional permission: |
| 119 | "os.telemetry.serial_number" with string |
| 120 | "Read Chrome OS device and component serial numbers" |
| 121 | |
| 122 | 2. `OemData.oemData` requires additional permission: |
| 123 | "os.telemetry.serial_number" with string |
| 124 | "Read Chrome OS device and component serial numbers" |
| 125 | |
| 126 | 3. `Batteryinfo.serialNumber` requires additional permission: |
| 127 | "os.telemetry.serial_number" with string |
| 128 | "Read Chrome OS device and component serial numbers" |
| 129 | |
| 130 | 4. MAC Address in `InternetConnectivity` requires additional permission: |
| 131 | “os.telemetry.network_info” with string “Read ChromeOS network information” |
| 132 | |
Bastian Kersting | 18c9e72 | 2022-08-17 09:11:11 | [diff] [blame] | 133 | # The Chrome extension |
| 134 | |
| 135 | In order for a Chrome extension to have access to telemetry and diagnostics |
| 136 | APIs, the following requirements need to be satisfied: |
| 137 | |
| 138 | 1. The user must be either: |
| 139 | |
| 140 | a. managed and the Telemetry extension was force-installed via policy, or |
| 141 | |
| 142 | b. The user is the device owner (the first user of the device). |
| 143 | |
Chung-Sheng Wu | b713ab0 | 2023-07-21 15:56:20 | [diff] [blame] | 144 | c. The user is in Shimless RMA flow. |
| 145 | |
Bastian Kersting | 18c9e72 | 2022-08-17 09:11:11 | [diff] [blame] | 146 | 2. The PWA UI associated with the Telemetry extension must be opened for the |
| 147 | extension to have access to APIs. |
| 148 | |
| 149 | 3. The device hardware must belong to the OEM associated with the Telemetry |
| 150 | extension (e.g. HP Support Assist only runs on HP devices). |
| 151 | |
| 152 | 4. Only an allowlisted extension ID can access Telemetry Extension APIs. Each |
| 153 | allowlisted extension ID can be connected to one PWA origin. It is mandatory |
| 154 | to declare one entry in `externally_connectable.matches` list. |
| 155 | An example can be found here: |
| 156 | ```json |
| 157 | "externally_connectable": { |
| 158 | "matches": ["https://third-party.com/*"] |
| 159 | } |
| 160 | ``` |
| 161 | |
| 162 | The `externally_connectable` key determines whether or not a website (or other |
| 163 | Chrome extension) can initiate communication with a Telemetry Extension. A |
| 164 | Telemetry Extension can always choose to communicate with sites indirectly via |
| 165 | content scripts injected into a tab. Please note that no matter what, |
| 166 | extensions should always validate and sanitize messages. An extension should |
| 167 | never have a listener that evals random code sent in a message. This helps |
| 168 | mitigate the damage a sender (whether untrusted or compromised) may be able to |
| 169 | perform. This is also critical because other Chrome extensions may be running |
| 170 | on the site that tries to connect to the Telemetry Extension and can initiate |
| 171 | that connection. |
| 172 | |
| 173 | # Development / Testing support |
| 174 | |
| 175 | ## Overriding PWA origin (Since M98) / Manufacturer (Since M105) |
| 176 | |
| 177 | Support for overriding the PWA origin and manufacturer to use while development |
| 178 | and testing was added in version M98 and M105. The PWA origin option overrides |
| 179 | the allowlisted PWA origin while the manufacturer overrides the actual device |
| 180 | manufacturer fetched from cros_config. Here is what you need to do in order to |
| 181 | access the flags (you can skip to step 3 if you already have read/write access |
| 182 | to rootfs): |
| 183 | |
| 184 | 1. On your testing device, make sure you enable developer mode. |
| 185 | |
| 186 | 2. Make sure you have write access to rootfs, if not run `/usr/share/vboot/bin/make_dev_ssd.sh --remove_rootfs_verification` |
| 187 | |
| 188 | 3. Open `/etc/chrome_dev.conf` and add these lines to the end: |
| 189 | ``` |
| 190 | --telemetry-extension-pwa-origin-override-for-testing=<new-pwa-origin> |
| 191 | --telemetry-extension-manufacturer-override-for-testing=<new-manufacturer> |
| 192 | ``` |
| 193 | |
| 194 | <ol start="4"> |
| 195 | <li>In your Telemetry Extension's manifest.json, set the |
| 196 | externally_connectable.matches entry to match <new-pwa-origin>.</li> |
| 197 | </ol> |
| 198 | |
| 199 | After following those steps, the new PWA and the Telemetry Extension should be |
| 200 | able to communicate via message passing. |
| 201 | |
| 202 | ## A Note on Serial Number |
| 203 | |
| 204 | The device serial number can be accessed using `dpsl.telemetry.getVpdInfo()` |
| 205 | and the battery serial number is accessed using `dpsl.telemetry.getOemDataInfo()`. |
| 206 | Because of the sensitive nature of serial numbers, this information is guarded |
| 207 | using a runtime permission: `os.telemetry.serial_number`. |
| 208 | For technical limitation, this is now a mandatory permission, meaning the |
| 209 | chrome extension’s manifest.json needs to include it in the permissions list in |
| 210 | order to have access to serial numbers. |
| 211 | |
Bastian Kersting | 7280fe84 | 2022-08-29 12:46:31 | [diff] [blame] | 212 | ## Setup a secure connection on localhost |
| 213 | |
| 214 | The Telemetry Extension enforces `https` as the protocol for communicating with |
| 215 | the PWA. During development, this leads to a rejection of a PWA hosted under |
| 216 | `http://localhost/` or another origin that does not have a valid certificate |
| 217 | that is trusted by Chrome. The following steps describe how to set up a secure |
| 218 | development PWA under crostini (Linux on ChromeOS). For this guide we assume |
| 219 | `localhost` as the host. Please note that the `openssl` commands for this |
| 220 | guide were taken from |
| 221 | [this](https://www.section.io/engineering-education/how-to-get-ssl-https-for-localhost/) |
| 222 | blog post. |
| 223 | |
| 224 | * Setup crostini (`Settings>Developers>Linux development environment`) and make |
| 225 | sure that "My Files" are shared with Linux (right click on the "My Files" folder |
| 226 | and then select "Share with Linux"). |
| 227 | * Navigate to a shared folder under `mnt/chromeos/..` and run the following |
| 228 | command to create a root certificate: |
| 229 | ``` |
| 230 | openssl genrsa -out CA.key -des3 2048 |
| 231 | ``` |
| 232 | * Using this key, generate a root certificate: |
| 233 | ``` |
| 234 | openssl req -x509 -sha256 -new -nodes -days 3650 -key CA.key -out CA.pem |
| 235 | ``` |
| 236 | * Next up, create a file named `localhost.ext` with the following content: |
| 237 | ``` |
| 238 | authorityKeyIdentifier = keyid,issuer |
| 239 | basicConstraints = CA:FALSE |
| 240 | keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment |
| 241 | subjectAltName = @alt_names |
| 242 | |
| 243 | [alt_names] |
| 244 | DNS.1 = localhost |
| 245 | IP.1 = 127.0.0.1 |
| 246 | ``` |
| 247 | * Now create a key and a Certificate Signing Request (CSR) for localhost using |
| 248 | the following commands: |
| 249 | ``` |
| 250 | openssl genrsa -out localhost.key -des3 2048 |
| 251 | openssl req -new -key localhost.key -out localhost.csr |
| 252 | ``` |
| 253 | * Finally generate a Certificate for localhost with the following command: |
| 254 | ``` |
| 255 | openssl x509 -req -in localhost.csr -CA ../CA.pem -CAkey ../CA.key -CAcreateserial -days 3650 -sha256 -extfile localhost.ext -out localhost.crt |
| 256 | ``` |
| 257 | * For your convenience create a decrypted version of your key for localhost. |
| 258 | This can be used by your development instance. |
| 259 | ```` |
| 260 | openssl rsa -in localhost.key -out localhost.decrypted.key |
| 261 | ```` |
| 262 | |
| 263 | You can now use the generated key and certificate for localhost in your |
| 264 | development environment. In order for Chrome to trust the key used by your |
| 265 | application, you need to add the CA root certificate to Chrome. |
| 266 | Under `Settings>Privacy and security>Security>Manage certificates` you are |
| 267 | able to set the root CA. Just select the `Authorities` tab and click `Import`. |
| 268 | Select the generated `CA.pem` file and click open. Now your Chrome instance |
| 269 | and testing environment trust each other. |
| 270 | |
Bastian Kersting | db7db9f | 2022-11-30 17:29:00 | [diff] [blame] | 271 | [//]: <> (This section is part of the API terms of use, internal version is) |
| 272 | [//]: <> (here go/telemetry-extension-tos. DO NOT EDIT unless changes in source) |
| 273 | # Restrictions on Data Use |
| 274 | |
| 275 | Due to the powerful nature of this API there are limits on how the data can be |
| 276 | utilized: |
| 277 | |
| 278 | 1. This API can only be used to receive telemetry data and diagnostic |
| 279 | information from ChromeOS-based devices to provide Customer Support Services. |
| 280 | |
| 281 | 2. This API will only be used, access or otherwise process personal data or |
| 282 | device identifiers at the Customer’s express direction in each instance. |
| 283 | |
| 284 | 3. Company will not access the ChromeOS API on an ongoing basis, or at recurring |
| 285 | intervals, without express direction by the Customer. |
| 286 | |
| 287 | 4. Company will not store (on device or server), or use for geolocation |
| 288 | purposes, the device SSID or BSSID. |
| 289 | |
| 290 | 5. Company will not use data obtained through the API for marketing purposes. |
| 291 | |
| 292 | 6. Company will provide and adhere to a privacy policy that clearly and |
| 293 | accurately describes to Customers what data is collected and how the data is |
| 294 | used and shared. |
| 295 | |
Bastian Kersting | e8aea8a | 2022-11-25 13:46:18 | [diff] [blame] | 296 | # Further reads |
| 297 | |
| 298 | For information around configuration of certain cros-config values please visit: |
| 299 | |
| 300 | 1. [Customization Guide - OEM Name](add_oem_name.md) |
| 301 | |
| 302 | 2. [Customization Guide - Fingerprint Diagnostics](fingerprint_diag.md) |
| 303 | |
Bastian Kersting | 137a8a1c | 2023-04-26 15:04:07 | [diff] [blame] | 304 | 3. [Telemetry Extension API overview](api_overview.md) |
| 305 | |
Bastian Kersting | 18c9e72 | 2022-08-17 09:11:11 | [diff] [blame] | 306 | # FAQs |
| 307 | |
| 308 | Q: I found a bug, how do I report it?<br> |
| 309 | A: Thank you for your contribution. Please create a new bug with the description |
| 310 | and logs (if possible) on our |
Bastian Kersting | 6b8b21b | 2022-09-01 09:33:00 | [diff] [blame] | 311 | [bugtracker](https://partnerissuetracker.corp.google.com/issues/new?component=1225577&template=1725782). |
| 312 | You need a partner account to do that. |
Bastian Kersting | 18c9e72 | 2022-08-17 09:11:11 | [diff] [blame] | 313 | |
| 314 | Q: Have a question?<br> |
Bastian Kersting | e8aea8a | 2022-11-25 13:46:18 | [diff] [blame] | 315 | A: Please reach out to [email protected]. |