3.6.5. Diagnostic Database Update Plugin

Software Architecture: Diagnostic Database Update Plugin arch~plugin-diagnostic-database-update

Endpoints and Security

By default, all modifying actions to any endpoint require an exclusive vehicle lock. It must be ensured, that no diagnostic operations are in progress, when the “Apply” action is triggered - this includes functional and component locks.

Only the subject of the lock is allowed to use the endpoints. This ensures that the database isn’t used while it is being updated, and that no 3rd party could add additional files to the update while it is being prepared, which could lead to security issues.

This behavior and additional security requirements must be modifiable through a trait provided to the plugin, to support more specific OEM requirements for security and individual environments during the update process.

The diagnostic database update plugin must provide the following bulk-data categories/endpoints for file management, and a separate operations endpoint for applying/rolling back/cleaning up updates:

Bulk-Data Paths for Diagnostic Database Update Preparation

Method

Path

Description

GET

/apps/sovd2uds/bulk-data/runtimefiles-current

Return a list of items in the currently active diagnostic database.

GET

/apps/sovd2uds/bulk-data/runtimefiles-nextupdate

Returns a list of the next update of the diagnostic database. Initially it shows the existing diagnostic database, and applies all pending updates to it, to show the state of the diagnostic database after applying the pending updates.

POST

/apps/sovd2uds/bulk-data/runtimefiles-nextupdate

Adds files to the next update of the diagnostic database. Two content types are supported: multipart/form-data (one or more files, filenames taken from each part’s filename parameter), and application/octet-stream (a single file per request, whose filename must be provided via the Content-Disposition header, e.g. Content-Disposition: attachment; filename="foo.mdd"). Returns 201 with all created IDs and a Location header for the first created file.

DELETE

/apps/sovd2uds/bulk-data/runtimefiles-nextupdate

Removes all pending changes to the next update of the diagnostic database, to reset the state of the next update to the currently active database. Returns 200 with deleted_ids and errors.

DELETE

/apps/sovd2uds/bulk-data/runtimefiles-nextupdate/{id}

Deletes the file from the pending update - in case of a file that was previously part of the current database, it’ll be deleted in the current database upon applying the next update.

GET

/apps/sovd2uds/bulk-data/runtimefiles-backup

Returns a list of items of the previously used diagnostic database, which can be used to roll back the diagnostic database in case of issues.

DELETE

/apps/sovd2uds/bulk-data/runtimefiles-backup

Deletes the backup of the previously used diagnostic database, to free up storage space. This also means that rolling back to the previous state isn’t possible anymore after deleting the backup. Returns 200 with deleted_ids and errors.

Operations Paths for Applying/Rolling Back/Cleaning Up Diagnostic Database Updates

Method

Path

Description

GET

/apps/sovd2uds/operations/runtimefilesupdate/executions

Returns the list of current execution identifiers. Always contains at most one entry.

GET

/apps/sovd2uds/operations/runtimefilesupdate/executions/{id}

Returns the status of a specific execution by its ID.

POST

/apps/sovd2uds/operations/runtimefilesupdate/executions

Starts a new execution (Apply, Rollback, or Cleanup). Returns 202 Accepted with the execution ID.

Note

The following query parameters must be supported for the GET endpoints:

  • x-sovd2uds-include-hash (string, default: not present – supported is only sha256) - to include file hashes of the files

  • x-sovd2uds-include-file-size (boolean, default: false) - to include file sizes of the files

  • x-sovd2uds-include-revision (boolean, default: false) - to include the revision inside the files

  • created-after and created-before (string:date-time) are accepted for ISO 17978-3 compatibility but do not currently filter results.

The runtime update plugin accepts MDD database files (.mdd). CDA configuration files cannot be updated through the runtime-files endpoints.

Limitations to bulk-data operations

For Security reasons, none of the endpoints should allow retrieval of the files by default - there may be an option to enable it. Adding or deleting files must only be allowed in the runtimefiles-nextupdate category, and not for the runtimefiles-backup or runtimefiles-current category, to avoid security issues, and to ensure consistency of the backup and current state of the diagnostic database.

File Handling

The id for the files within the diagnostic database update plugin must be the file name, to ensure consistency when files are overwritten, deleted, or added.

File names must be handled case-insensitively on all operating systems to make usage regardless of OS consistent, to avoid duplicated entries, and to allow case-insensitive paths for deletion.

There must be an option to normalize file names to the name of the ECU they belong to, to ensure consistency and to avoid duplicated entries for the same ECU with different file names.

Files must be verifiable through a trait provided to the plugin before being applied as the new current state.

The verification includes, but is not limited to, signature verification, hash verification, and version checks of the currently active database, as well as the new one.

Providing a Custom Update Plugin

Applications embedding CDA can replace the complete runtime update implementation at startup. Implement cda_interfaces::runtime_update_api::RuntimeFilesUpdatePlugin and pass a builder to Setup::with_update_plugin. The builder receives CdaRuntime, which exposes the live configuration, lock provider, storage directory, update guard, and reload-related infrastructure required by an implementation. The UDS manager and DoIP gateway are exposed only as replace-only capabilities (gateway_replacer, uds_manager_replacer, typed ReplaceComponent<_>): an implementation can install a freshly built replacement, but has no read access to the live component and therefore cannot drive UDS requests or enable transport directly. See docs/04_adr/06_deferred_initialization.rst for the rationale.

The update_plugin_fn helper adapts an async closure without requiring a separate builder type:

use opensovd_cda_lib::{Setup, run_with_ext_from_config};
use opensovd_cda_lib::update::update_plugin_fn;

let setup = Setup::<MySecurityPlugin, MySecurityLoader>::new()
    .with_update_plugin(update_plugin_fn(|runtime| async move {
        Ok(MyRuntimeUpdatePlugin::new(runtime))
    }));

run_with_ext_from_config(config, setup).await?;

CDA mounts the returned plugin on the standard runtimefiles-* endpoints and wraps it with read/write mutual exclusion. A replacement plugin therefore implements the complete update lifecycle (listing, upload, deletion, apply, rollback, cleanup, and execution status).

Implementations that only need custom authorization, signature checks, version policy, or reload behavior should normally retain DefaultRuntimeUpdatePlugin and provide custom RuntimeUpdateSecurityPlugin and/or RuntimeReloaderPlugin implementations instead.

Application of the update

To delete all pending updates from runtimefiles-nextupdate, or to delete the backup in runtimefiles-backup DELETE on the respective bulk-data endpoint must be supported.

To apply all the pending updates to the current diagnostic database, an additional endpoint is required:

POST /apps/sovd2uds/operations/runtimefilesupdate/executions with a JSON-payload containing a parameters object with the property mode, following the standard convention of wrapping operation-specific inputs in a parameters field, with the following possible values for mode (all case-insensitive):

  • Apply - to apply the pending updates.

  • Rollback - to roll back to the backup state of the diagnostic database (also clears pending nextupdate)

  • Cleanup - to reset all pending updates, as well as deleting the backup

Execution Lifecycle

Only one execution can be in-flight at a time. Starting a new execution while one is already running must be rejected with a conflict error.

Execution entries are retained in memory and remain queryable via GET /apps/sovd2uds/operations/runtimefilesupdate/executions/{id} until the next execution is started. When a new execution is started, all previous terminal-state (Completed or Failed) entries are removed. Entries must not be removed based on time (no TTL). This ensures that the result of the last execution remains available for inspection without requiring indefinite memory growth.

The list endpoint GET /apps/sovd2uds/operations/runtimefilesupdate/executions returns all currently tracked execution identifiers and always contains at most one entry. No vehicle lock is required to use the list or status endpoints.

After applying, or rolling back the diagnostic database, the new database must be active immediately, without requiring a restart of the CDA, and the old state must be available as a backup until the next update is applied, the backup is deleted, or a cleanup is initiated. The state of nextupdate must also be reset after applying or rolling back, to ensure that pending updates aren’t reapplied unintentionally after a rollback, and to ensure that the state of the next update is consistent with the currently active database.

Atomicity

Every action must be atomically applied, meaning that if any part of the action fails, the entire action must be rolled back, and the state of the diagnostic database while the adapter is running must be consistent with either the state before the action, or the state after the action, but not a partially applied state.

This also applies to power cycles and crashes during the application of the update, to ensure this, journaling and transactional file handling can be used, but the exact mechanism is up to the implementation of the plugin. This may require flushing filesystem caches frequently to guarantee consistency.