OTA Connect Developer Guide

Get started

What is libaktualizr?

Libaktualizr is a C++ library providing API access to the functionality that aktualizr provides.

Aktualizr vs. libaktualizr
  • Aktualizr is a C++ application that implements the client-side functionality for OTA Connect according to the Uptane security framework. It is designed to be run as a standalone component on an embedded system, and can manage the entire software update process. In implementation, it is actually a relatively thin wrapper around libaktualizr.

  • libaktualizr provides a C++ API allowing developers to integrate OTA Connect updates with Uptane security into their own custom applications.

How to build libaktualizr

Before you can work with libaktualizr, you must build the main aktualizr project.

Aktualizr is an open-source software project distributed under the Mozilla Public License 2.0 and is located on github: https://github.com/advancedtelematic/aktualizr

You should build the project on a Linux system and your compiler must support the C++11 version of the standard.

The project contains more dependencies than is practical to list here, so have a look at the main readme for the aktualizr project.

The README contains an extended description on how to build aktualizr as well as the list of build and run-time dependencies.

Once you have installed the dependencies, build the aktualizr project with the following commands:

git clone --recursive https://github.com/advancedtelematic/aktualizr.git
cd aktualizr
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make
The --recursive flag in the git clone command is needed to recursively clone all the git submodules.

After the build is finished, you’ll find the client library at the following location: ${PROJECT_ROOT}/build/src/libaktualizr/libaktualizr_lib.so.

Integrating libaktualizr into your application

To integrate libaktualizr in your application, you must first decide on one of the following build options:

  • Build libaktualizr "in tree" by adding it to an existing cmake project (recommended).

  • Build libaktualizr "out-of-tree".

Building libaktualizr in-tree

The easiest way to integrate with libaktualizr is to add it as a subdirectory to your cmake project.

To build libaktualizr in-tree, follow these steps:
  1. Clone the aktualizr into your project directory:

    $ git clone --recursive https://github.com/advancedtelematic/aktualizr.git
  2. Add it to your CMakeLists.txt:

    add_subdirectory(aktualizr)

    This command automatically adds the needed entries to INCLUDE_DIRECTORIES variable, create the AKTUALIZR_EXTERNAL_LIBS variable, which contains the list of external libraries required for linking with libaktualizr, and create the aktualizr_static_lib and aktualizr_lib targets.

  3. Do a test build of your application

    Whenever you build your application you must add these libraries as follows:

    target_link_libraries(your-app aktualizr_lib)

    Or:

    # DEPRECATED!
    target_link_libraries(your-app aktualizr_static_lib ${AKTUALIZR_EXTERNAL_LIBS})

    You also might need to add the following line if you are using boost libraries:

    add_definitions(-DBOOST_LOG_DYN_LINK)

Building libaktualizr out-of-tree

If you don’t want to make libaktualizr part of your cmake project, it’s also possible to build libaktualizr out-of-tree. In this case you will need to specify the required libraries and includes for your application manually. Refer to your system’s documentation on how to specify additional libraries and include directories for the target application.

Here’s an example of how to specify the required libraries for an out-of-tree build in cmake project:

target_link_libraries(your-app aktualizr_lib)
target_link_libraries(your-app pthread)
target_link_libraries(your-app archive)
target_link_libraries(your-app boost_atomic)
target_link_libraries(your-app boost_chrono)
target_link_libraries(your-app boost_date_time)
target_link_libraries(your-app boost_filesystem)
target_link_libraries(your-app boost_log)
target_link_libraries(your-app boost_log_setup)
target_link_libraries(your-app boost_program_options)
target_link_libraries(your-app boost_regex)
target_link_libraries(your-app boost_system)
target_link_libraries(your-app boost_thread)
target_link_libraries(your-app crypto)
target_link_libraries(your-app curl)
target_link_libraries(your-app sodium)
target_link_libraries(your-app sqlite3)
target_link_libraries(your-app ssl)

target_include_directories(your-app PRIVATE ${AKTUALIZR_PROJECT_DIR}/src/libaktualizr)
target_include_directories(your-app PRIVATE ${AKTUALIZR_PROJECT_DIR}/third_party/jsoncpp)

add_definitions(-DBOOST_LOG_DYN_LINK)

How to use the libaktualizr API

Libaktualizr provides a C++ API for fetching information about available updates and currently running OTA campaigns, downloading and installing the updates, and reporting the installation results.

If you’re yet not familiar with OTA Connect concepts such as "campaigns", have a look at the OTA web app first. You might need to register for a free developer account first.

The main library header is primary/aktualizr.h. It also includes few other libaktualizr headers.

To use the API, add the src/libaktualizr directory to your include path and add # include "primary/aktualizr.h" to your source file.

When using the API, consider the following points:

  • Most of the API calls, unless specified otherwise, are asynchronous and return a std::future which contains the corresponding result type.

  • Result types are defined in the primary/results.h header.

  • Asynchronous commands are posted to the command queue and executed in sequential order in a separate thread.

  • If the execution is paused, newly issued commands accumulate in the command queue and it’s up to the caller to ensure that the queue doesn’t get overloaded with unnecessary duplicate commands.

For an example of how to use the libaktualizr API as a primary ECU, there are two applications that you can use as references. Aktualizr itself is in src/aktualizr_primary, and there is a very simple demo of using libaktualizr via the API (for example, to get user consent) named libaktualizr-demo-app.

API Description

General management, configuration and control flow

The configuration options depend on the used provisioning type and the local storage which you use to store updates and metadata. For description of all configuration options, refer to the client configuraton reference documentation and to the config folder for configuration examples.

  • Add a new secondary ECU

    void Aktualizr::AddSecondary(const std::shared_ptr<Uptane::SecondaryInterface> &secondary)

    You must call this function before you call Initialize. To find out more about primary and secondary ECUs, see our Uptane description.

  • Initialize aktualizr

    void Aktualizr::Initialize()

    Any secondary ECUs should be added before making this call. This will provision with the server if required. This must be called before using any other aktualizr functions except AddSecondary.

  • Set a callback to receive event notifications

    boost::signals2::connection Aktualizr::SetSignalHandler(std::function<void(shared_ptr<event::BaseEvent>)> &handler)

    Returns a signal connection object, which can be disconnected if desired. The events are defined in the primary/events.h header.

  • Pause a command

    void Aktualizr::Pause()

    Requests the currently running command to pause and freezes the command queue. All commands that were scheduled after the currently executed command will wait in the command queue until Resume() is issued. Commands that are issued after Resume() will be put on a command queue, but not executed until Resume() is called. The Pause() function returns immediately, while pausing the running command still may be in progress. The function has no effect if the execution was already paused.

  • Resume a paused command

    void Aktualizr::Resume()

    Resumes the execution of a previously paused command and all subsequent commands in the command queue. Returns immediately. The function has no effect if the execution was not paused.

  • Abort execution

    void Aktualizr::Abort()

    Requests the currently running command to abort and flushes the command queue. The Abort() function will block until the command queue is empty and all currently executing commands have stopped. You can also call Abort() on a previously paused class instance, this will clean the command queue, but aktualizr will remain in the paused state. To continue execution at some later point one needs to call Resume().

    Abort() is also called by the Aktualizr class destructor.

Campaign management commands

  • Check for campaigns

    std::future<result::CampaignCheck> Aktualizr::CampaignCheck()

    The term "campaign" has a specific meaning in OTA Connect. A campaign allows users to approve updates and deploy them to devices.

  • Accept a campaign

    std::future<void> Aktualizr::CampaignAccept(const std::string &campaign_id)

    A campaign contains an update which must be accepted by the end user (or on behalf of the end user) before it can be installed on the device. This call accepts the campaign so that the update can be installed.

Update management commands

  • Send local device data to the server

    std::future<void> Aktualizr::SendDeviceData()

    This data includes network status, installed packages and hardware information.

  • Check for updates

    std::future<result::UpdateCheck> Aktualizr::CheckUpdates()

    Fetches Uptane metadata and check for updates. This collects a client manifest, PUTs it to the director, updates the Uptane metadata (including root and targets), and then checks the metadata for updates to the target software.

  • Download target files

    std::future<result::Download> Aktualizr::Download(const std::vector<Uptane::Target> &updates)

    Downloads the target files that are specified in the input vector returned by CheckUpdates.

  • Install software from target files

    std::future<result::Install> Aktualizr::Install(const std::vector<Uptane::Target> &updates)

    Installs the software contained in the previously downloaded target files.

  • Get a handle for downloaded target

    std::ifstream Aktualizr::GetStoredTarget(const Uptane::Target &target)

    Get target downloaded in Download call. Returned target is guaranteed to be verified and up-to-date according to the Uptane metadata downloaded in CheckUpdates call.

Miscellaneous commands

  • Synchronously check for updates and install them

    void Aktualizr::UptaneCycle()

    Synchronously runs an "Uptane cycle" which checks for software updates, downloads any new target files, installs the update, and sends a manifest back to the server.

  • Asynchronously run aktualizr

    std::future<void> Aktualizr::RunForever()

    Automatic check and install updates indefinitely: runs UptaneCycle() in a loop at regular intervals until the destructor is called.