How software update applications integrate with swu-core

The swu-core API provides a comprehensive interface for integrating the modules that implement parts of a software update application with the core update library.

Discovery

The Discovery module creates Update objects by loading manifest files in a call to swu_client_create_updates(). To find manifest files, the discovery code could monitor attached USB devices. Or, it could communicate with a server to request manifest files. Regardless of how it finds manifest files (and their associated update packages), the Discovery module must call swu_client_create_updates() to process them.

The following sample code creates Update objects based on a manifest file:

/* Function is called when a manifest file was located.
   The manifest ID is returned so that the updates can later be
   released with a call to swu_client_release_updates(). */

swu_manifest_id_t manifest_file_found ( const char* path ) 
{
    swu_result_t result;
    swu_manifest_id_t id;
 
    /* Create the updates for the given path */
    result = swu_client_create_updates( path, &id );
   
    if ( result == SWU_RESULT_SUCCESS ) 
    {
        /* Updates are created and should be accessible
            through the list of installed updates (accessed 
            with swu_client_get_install_update_list()) */
        return id;
    } 
    else 
    {
        return SWU_INVALID_MANIFEST_ID;
    }
}

HMI

A software update application may need to perform many HMI-related tasks to provide the user with sufficient information and control over the update process. The following tasks can be completed in the HMI module by using the swu-core library:

  1. Displaying the list of available updates

    Typically, an HMI needs to display the list of available software updates. The user can navigate this list, display information about the updates, and then accept or decline each update. To support this interaction, the library provides the UpdateList data type, which allows you to hold a list of Update objects. There are several functions for working with UpdateList objects:

    swu_client_get_install_update_list()
    Returns a handle to the list of software updates ready to be installed. You can then use this handle in the remaining functions listed to interact with the list.
    swu_update_list_get_length()
    Gets the length of the list of software updates.
    swu_update_list_iterate()
    Iterates over the Update objects in the list.
    swu_update_list_register_notification()
    Registers a swu_update_list_notification_t structure, which stores a callback in its change_notifier field, to receive notifications from an UpdateList.
    swu_update_list_unregister_notification()
    Unregisters a structure from receiving notifications.

    After getting the handle to the list of available updates by calling swu_client_get_install_update_list(), your client application can register for notifications by calling swu_update_list_register_notification(). When the UpdateList object changes (e.g., because Update objects are added to or removed from the list), the library calls the callback in the registered swu_update_list_notification_t structure to notify the client of the list update. This callback can refresh the HMI to display the latest list contents by iterating through the list and processing its Update objects.

    The swu_update_list_iterate() function is the only way to access the contents of an UpdateList object. When calling this function, you must pass in a function pointer of the swu_update_list_iterator_t type to reference the code that processes list items. The library calls this iterator function on each Update object found in the list, and then one final time with a NULL value for the Update object to indicate the list's end. The callback function can stop the list iteration at any time by returning false instead of true, which tells the library to stop iterating through the list.

    The following diagram shows how the iteration work is shared between the software update application and the swu-core library:

    Figure 1. Interaction between the application and the swu-core library during UpdateList iteration

    This code sample shows how to process the UpdateList after it has changed:

    /* The function used as the swu_update_list_iterator_t 
       callback */
    bool iterate_list( swu_update_t update, 
                       void *context ) 
    {
        /* When iterating the list, the library calls this 
            function a final time with a NULL object reference to
            indicate the end of the list */
        if ( update != NULL ) 
        {
            /* Call the necessary APIs on the Update object */
            ....
        }
     
        /* Return true to continue iterating through the list */
        return true;
    }
    
    /* The function for reacting to a list update notification */ 
    void updatelist_changed( swu_update_list_t list, 
                             void *context )
    {
        /* Our list has changed--refresh the display by processing
            the current list items, using the specified callback 
            to iterate through the list */
        swu_update_list_iterate( list, iterate_list, NULL );
    }
    
  2. Displaying information about an update

    The Update object provides an access function for each of its properties. You can retrieve these properties and then display update information to the user. The property functions include:

    • swu_update_get_name()
    • swu_update_get_description()
    • swu_update_get_version()
    • swu_update_get_priorty()

    Further information on these and other Update functions can be found in the SWU library API.

    The following sample prints the name and version of an Update object to stdout. Because these functions all return handles to swu_string_t data items, the strings contained in these items must be released with a call to swu_object_release() after the caller is done with them.

    void print_update_object( swu_update_t update ) 
    {
        swu_string_t name;
        swu_string_t version;
     
        if ( swu_update_get_name( update, &name ) ==
                                          SWU_RESULT_SUCCESS )
        {
            printf("Object name is %s\n", name);
            swu_object_release(name);
        }
     
        if ( swu_update_get_version( update, &version ) ==
                                          SWU_RESULT_SUCCESS )
        {
            printf("Object version is %s\n", version);
            swu_object_release(version);
        }
    }
    
  3. Acting on an update

    To inform the library of the user's decision whether or not to install an update, the HMI module must call one of these two API functions:

    swu_update_accept_install()
    Requests installation of the software update to begin on the corresponding target.
    swu_update_decline_install()
    Declines installation of the software update.

    Typically, you call these functions after iterating through the list of updates and finding a particular Update object to take the action on.

  4. Installing an update

    After you accept the installation for an Update object, the library notifies the associated UpdateTarget object to begin the installation. To monitor the installation status, your software update application should call swu_update_register_notifications() to register callbacks so it will be notified when the state or progress of the installation changes. The swu_update_notifications_t structure contains two notification callbacks:

    state_changed
    Called when the Update object changes state, as shown in the State-transition diagram for Update objects.
    progress
    Called when the UpdateTarget indicates a change in progress while the Update object is in the SWU_UPDATE_STATE_INSTALLING or SWU_UPDATE_STATE_VERIFYING state.

    These notifications can be used to refresh progress bars in the HMI or process a change in the installation status. The change-of-status processing could involve displaying errors when necessary. For example, suppose the Update object transitions to the SWU_UPDATE_STATE_INSTALL_FAILED state. The client could then call swu_update_get_failure_info() to retrieve the failure code, and then display that code and other error information in the HMI or write this data to an error log.

    The following sample calls swu_update_accept_install() and then registers and monitors these callbacks:

    void handle_state_change( swu_update_t update, 
                              swu_update_state_t state, 
                              void *state_changed_context )
    {
        if ( state == SWU_UPDATE_STATE_INSTALL_FAILED ) 
        {
            swu_failure_info_t info;
            if ( swu_update_get_failure_info ( update, &info ) 
                                          == SWU_RESULT_SUCCESS ) 
            {
                /* Tell the user about the failure */
                ....
            }
        } 
        else 
        {
           /* Handle other state changes */
           ....
        }
    }
     
    void handle_progress_change( swu_update_t update, 
                                 swu_progress_t percent, 
                                 void *progress_context )
    {
        /* Refresh the progress percentage in the HMI */
        update_progress_display( update, percent );
    }
     
    static swu_update_notifications_t notifications = 
        { handle_progress_change, NULL, 
            handle_state_change, NULL };
     
    void accept_install( swu_update_t update ) 
    {
        if ( swu_update_accept_install( update ) == 
                                    SWU_RESULT_SUCCESS ) 
        {
             swu_update_register_notifications( 
                            update, &notifications );
        }
    }
    

UpdateTarget

Each UpdateTarget object supports installing a software update on a target system. You can register multiple UpdateTarget objects with the library, but each Update object that you create can work with only one UpdateTarget.

An update application must do these tasks for an UpdateTarget:

  1. Register with the library

    Before it can install a software update, an UpdateTarget must be registered with the library. Through the swu_target_register() function, you can provide the library with the target's vendor ID and hardware ID (for identifying it) and with a pointer to an swu_target_interface_t structure (for communicating with it). Multiple UpdateTarget objects may share the same swu_target_interface_t, but each of these registered objects must have a unique combination of vendor ID and hardware ID to distinguish it from other targets.

    When the registration succeeds, the library returns an swu_target_id_t handle, which you must use to refer to that same UpdateTarget in subsequent API calls.

    The following sample shows a simple UpdateTarget registration:

    swu_target_id_t register_target( const char *vendor_id,
                                     const char *hardware_id )
    {
        /* We define only the get_info() and install() function
            pointers in this interface */
        swu_target_interface_t interface = {get_target_info, NULL,
                                            NULL, NULL,
                                            install_update, NULL,
                                            NULL, NULL,
                                            NULL, NULL,
                                            NULL, NULL};
     
        /* Store the ID assigned by the swu-core library. 
            The ID is needed in future API calls. */
        swu_target_id_t assigned_id;
     
        if ( swu_target_register( vendor_id, 
                                  hardware_id, 
                                  &interface, 
                                  &assigned_id ) == 
                                      SWU_RESULT_SUCCESS ) 
        {
            return assigned_id;
        } 
        else 
        {
            return SWU_INVALID_TARGET_ID;
        }
    }    
    
    Note: In this sample, most function pointers in the swu_target_interface_t structure are left undefined. The swu-core library considers any function that has a reference pointer of NULL to be unsupported. In this case, the library skips that step in the software update process and tries to continue the installation at the next step.
  2. Retrieve information about the target

    The function defined by the get_info() pointer in the UpdateTarget interface retrieves the properties describing the current version of software installed on the target. The library calls this interface function when handling a call to the swu_target_get_info() API function and after an update was successfully verified by an UpdateTarget. In the latter case, the get_info call ensures that the library has up-to-date target information following a successful update, which might have changed some aspect of the UpdateTarget.

  3. Implement software update functions

    To carry out the update process, the library calls the functions referenced by the pointers in the swu_target_interface_t structure. In each of these functions, the UpdateTarget must call a success or failure function at some point to tell the library whether to continue with the update process.

    The interaction between the UpdateTarget object and the library proceeds like this:

    1. When a call from the HMI module to swu_object_accept_install() completes successfully, the library calls the prepare_to_install() function defined for the UpdateTarget. In this function, the UpdateTarget examines its state to determine whether it can install the update. If so, the UpdateTarget calls swu_target_ready_to_install(); if not, it calls swu_target_not_ready_to_install(). If no prepare_to_install() function is defined, the library skips this step.

    2. Next, the library calls the provided install() function and the UpdateTarget begins installing the software update. During the installation, the UpdateTarget can call swu_target_install_progress() to inform the swu-core library (and any registered listeners of the associated Update object) of the installation progress.

      If the installation succeeds, the UpdateTarget calls swu_target_install_successful(); otherwise, it calls swu_target_install_failed().

    3. When the installation completes, the library calls the provided verify_update() function so the UpdateTarget can verify the installation. During the verification, the UpdateTarget can call swu_target_verification_progress() to inform the swu-core library (and any registered Update listeners) of the verification progress.

      If the verification succeeds, the UpdateTarget calls swu_target_verification_successful(); otherwise, it calls swu_target_verification_failed().

      If the UpdateTarget doesn't support verification of update installations, which means its verify_update() function pointer is set to NULL, the library skips the verification step.

    A successful update installation involving all three phases—preparation, installation, and verification—is shown in the diagram that follows. The diagram lists the Update object state changes and follow-up actions taken by the library in response to notifications it receives from the UpdateTarget:

    Figure 2. Interaction between an UpdateTarget object and the swu-core library during an update installation

Configuration

You can write a Configuration module that sets configuration attributes that apply to all updates.

The UpdateClient data type stores and exposes, through the swu-core library API, these attributes:

Client ID
read-only
An ID field that uniquely identifies an UpdateClient. This field is set during library initialization.
Local updates
read/write
Enables or disables local (e.g., USB or flash) software updates for the UpdateClient.
Update grace period
read/write
Grace period for accepting software updates, which indicates how long (in seconds) an update will be available for installation. This attribute setting is used for software updates that don't define their own grace period.
Maximum update retries
read/write
Maximum number of retries allowed for a software update. Note that this attribute is currently unused.

The following code demonstrates how to get and set the update grace period:

/* Get the update grace period */
swu_result_t client_config_get_update_grace_period( 
                                    swu_timestamp_t *period )
{
 
    swu_result_t result = 
      swu_client_configuration_get_update_grace_period( period );
    
    if ( result != SWU_RESULT_SUCCESS ) 
    {
        printf(
          "Error getting update grace period from swu client\n");
    }
 
    return result;
}
 
/* Set the update grace period */
swu_result_t client_config_set_update_grace_period(
                                    swu_timestamp_t period )
{
    swu_result_t result = 
      swu_client_configuration_set_update_grace_period( period );
    
    if ( result != SWU_RESULT_SUCCESS )
    {
        printf(
          "Error setting update grace period on swu client\n");
    }
 
    return result;
}