Client

Differences between revisions 16 and 46 (spanning 30 versions)
Revision 16 as of 2013-08-19 18:02:03
Size: 11790
Editor: mail
Comment:
Revision 46 as of 2014-06-24 14:25:47
Size: 19455
Editor: mail
Comment:
Deletions are marked like this. Additions are marked like this.
Line 38: Line 38:
The client will export a DBus API on the system bus which will allow for a u/i in the System Settings to query, begin, cancel, and apply a system update. This service starts via DBus activation and exits automatically after a configurable amount of time (i.e. it does not run forever). It maintains state such that the client can exit and get restarted to continue the update, even across reboots. The client uses the [[../Downloader|download service]] to manage all file downloads. Here is the DBus API specification: The client will export a DBus API on the system bus which will allow for a [[SoftwareUpdates#Phone|u/i in the System Settings]] to query, begin, cancel, and apply a system update. This service starts via DBus activation and exits automatically after a configurable amount of time (i.e. it does not run forever). It maintains state such that the client can exit and get restarted to continue the update, even across reboots. The client uses the [[../Downloader|download service]] to manage all file downloads. Here is the DBus API specification:
Line 43: Line 43:
Sent in response to '''!CheckUpdateStatus()''' async calls, this signal provides information about the state of the update. Sent in response to '''!CheckForUpdate()''' async calls, this signal provides information about the state of the update.
Line 46: Line 46:
 * ''available_version'' - integer specifying the candidate build number we plan to update to.  * ''available_version'' - string specifying the update target candidate version.
Line 48: Line 48:
 * ''last_update_date'' - the ISO 8601 format date (to the second) that the last update was applied to this device.  * ''last_update_date'' - the ISO 8601 format UTC date (to the second) that the last update was applied to this device.  This will be the empty string if no update has been previously applied.
Line 56: Line 56:
 * ''percentage'' - integer between 0 and 100 indicating how much of the download (not including preliminary files) have been currently downloaded.
 * ''eta'' - estimated time remaining to complete the download, in integer seconds
 * ''percentage'' - integer between 0 and 100 indicating how much of the download (not including preliminary files) have been currently downloaded. This may be 0 if we do not yet know what percentage has been downloaded.
 * ''eta'' - estimated time remaining to complete the download, in float seconds. This may be 0 if we don't have a reasonable estimate.
Line 64: Line 64:
Sent when the currently in progress update has been completely and successfully downloaded. When this signal is received, it means that the device is ready to have the update applied (typically by issuing a system reboot). Sent when the currently in progress update has been completely and successfully downloaded. When this signal is received, it means that the device is ready to have the update applied via '''!ApplyUpdate()'''.
Line 67: Line 67:
Sent when the update failed for any reason (including cancellation). The client will remain in the failure state until a '''!CheckUpdateStatus(0)''' or '''!CheckUpdateStatus(2)''' call is made.
 * ''consecutive_failure_count'' - an integer specifying the number of times in a row that a '''!CheckUpdateStatus()''' has resulted in an update failure. This increments until an update completes successfully (i.e. until the next '''!UpdateDownloaded()''' signal is issued).
 * ''last_reason'' - a string containing the English reason for why this updated failed.
Sent when the update failed for any reason (including cancellation, but only if a download is in progress). The client will remain in the failure state until the next '''!CheckForUpdate()''' call.
 * ''consecutive_failure_count'' - an integer specifying the number of times in a row that a '''!CheckForUpdate()''' has resulted in an update failure. This increments until an update completes successfully (i.e. until the next '''!UpdateDownloaded()''' signal is issued).
 * ''last_reason'' - a UTF-8 string containing the English reason for why this updated failed.

'''Rebooting(status)'''<<BR>>
Sent just before the device reboots.
 * ''status'' - a boolean indicating whether the application of the update is successful or not. Generally, when ''status'' is {{{true}}} you won't ever receive the signal because the device will reboot. When ''status'' is {{{false}}} it means the application of the update or reboot failed for some reason.

'''!SettingChanged(key, value)'''<<BR>>
Sent when a setting is changed. This signal is ''not'' sent if the new value is the same as the old value.
 * ''key'' - the key of the value that was changed.
 * ''value'' - the new value for the key.
Line 73: Line 82:
'''!CheckUpdateStatus(retry, resume)'''<<BR>>
Asynchronous call instructing the client to check for an available update. If a check is already in progress, it continues.  If the client is in ''auto-download'' mode (see below), then this call will both check the server for an available update, and automatically initiate the download of an available update. If the client is in ''manual-download'' mode, then the downloading of any available update will ''not'' occur automatically. It is also possible for the download to only occur automatically if other criteria are met, e.g. we are not on a wifi, or the device has a low battery.
 * ''retry'' - boolean flag (default {{{false}}}) indicating whether to retry a download if the previous one failed. If a previous update check or download failed and this flag is {{{true}}}, reset state and begin a new update, otherwise send an '''!UpdateFailed''' signal, incrementing the ''consecutive_failure_count''.
 * ''res
ume'' - boolean flag (default {{{false}}}) indicating whether a paused update should be resumed. If a previous update has been paused, it will be resumed if this flag is {{{true}}}, otherwise paused updates will not be resumed, but new updates will be started and in-progress updates will be continued.
In all cases, an '''!UpdateAvailableStatus''' signal will be issued once an update candidate is determined to be available;, the arguments can have the following
values:
'''!CheckForUpdate()'''<<BR>>
Asynchronous call instructing the client to check for an available update. If a check is already in progress, it continues. If the client is in ''auto-download'' mode (see below), then this call will both check the server for an available update, and automatically initiate the download of an available update. If the client is in ''manual-download'' mode, then the downloading of any available update will ''not'' occur automatically (use '''!DownloadUpdate()''' explicitly to start the download). It is also possible for the download to only occur automatically if other criteria are met, e.g. we are not on a wifi, or the device has a low battery. Note that '''!CheckForUpdate()''' will never resume a download.

In all cases, an '''!UpdateAvailableStatus''' signal will be issued once an update candidate is determined to be available; the arguments can have the following values:
Line 82: Line 90:
If we are in auto-download mode, an '''!UpdateProgress()''' signal is sent as soon as the download is started, usually with a {{{percentage}}} of 0 and an {{{eta}}} of 0.

'''!DownloadUpdate()'''<<BR>>
Asynchronous method to download an available update. No-ops if there is no update to download, an automatic download is already in progress, '''!CheckForUpdate()''' was not called first, or the update status is in an error condition. If a previous download was paused, this resumes the download. As with auto-download mode, an '''!UpdateProgress()''' signal is sent as soon as the download is started.
Line 83: Line 96:
Synchronous method to apply the update and initiate the reboot. Because the success path leads almost immediately to a reboot, the return value of this method is not meaningful (but will in practice be the empty string). In the failure case, the return value is a UTF-8 English string indicating the cause of the failure. Asynchronous method to apply the update and initiate the reboot. No-ops if no new update has been downloaded. Because the success path leads almost immediately to a reboot, this method does not return anything, but a '''Rebooting''' signal is sent.
Line 86: Line 99:
Synchronous method to cancel any update check or download in progress. No value is returned. Synchronous method to cancel any update check or download (even finished or paused) in progress. The empty string is returned unless an error occurred, in which case the error message is returned as a UTF-8 English string.
Line 89: Line 102:
Synchronous method to pause the current download. Returns a flag indicating whether the download was successfully paused.

'''!ResumeDownload()'''<<BR>>
Synchronous method to resume the current download. Returns a flag indicating whether the download was successfully resumed.
Synchronous method to pause the current download. The empty string is returned unless an error occurred, in which case the error message is returned as a UTF-8 English string.

'''Info()'''<<BR>>
Get information about the system images, similar to what is available via {{{system-image-cli --info}}}. Returns the following pieces of information.
 * '''current build number''' - integer
 * '''device name''' - string
 * '''channel name''' - string
 * '''last update date''' - ISO 8601 UTC format string, with second resolution, e.g. '''"YYYY-MM-DDTHH:MM:SS"'''
 * '''version details''' - dictionary of strings-to-strings where the keys are component names and the values are version strings.

'''Info2()'''<<BR>>
Like '''Info()''', but returns extended information that includes the last time a '''!CheckForUpdate()''' was performed. Returns the following pieces of information.
 * '''current build number''' - integer
 * '''device name''' - string
 * '''channel name''' - string
 * '''last update date''' - ISO 8601 UTC format string, with second resolution, e.g. '''"YYYY-MM-DDTHH:MM:SS"'''
 * '''version details''' - dictionary of strings-to-strings where the keys are component names and the values are version strings.
 * '''last check date''' - ISO 8601 UTC format string, with second resolution, e.g. '''"YYYY-MM-DDTHH:MM:SS"'''

'''!FactoryReset()'''<<BR>>
Wipe the data partition and issue a reboot to recovery. Takes no arguments, but possibly sends a {{{Rebooting()}}} signal (depending on the race against the system reboot procedure). ''New in system-image 2.3.''
Line 95: Line 125:
Synchronous method to write or update a setting. {{{key}}} is always a UTF-8 string, {{{value}}} is any basic DBus type (e.g. string, integer, boolean). While any key/value pair may be set, only the following currently have useful semantics:
 * '''min_battery''' - The minimum battery strength which will allow downloads to proceed. If the batter level is less than this, an available download will not be automatically initiated, although an explicit '''!DownloadUpdate()''' call can force this.
 * '''auto_downloads''' - A tri-state (currently) value indicating whether downloads should normally proceed automatically if an update is available or not.
Synchronous method to write or update a setting. {{{key}}} and {{{value}}} are UTF-8 strings. While any key/value pair may be set, only the following currently have useful semantics:
 * '''min_battery''' - The minimum battery strength which will allow downloads to proceed. The value is the string representation of a number between 0 and 100 percent. If the battery level is less than this, an available download will not be automatically initiated, although an explicit '''!DownloadUpdate()''' call can force this.
 * '''auto_download''' - A tri-state (currently) value indicating whether downloads should normally proceed automatically if an update is available or not.  The value is the string representation of the following integer values.
Line 101: Line 131:
 * '''failures_before_warning''' - An integer value which is unused by the client, but stored here for use by the user interface.  * '''failures_before_warning''' - Unused by the client, but stored here for use by the user interface.
If the new value is different than the old value, or if this key was not previously set, a '''!SettingChanged(key, value)''' signal is sent.

For the values with semantics, any invalid value is ignored (i.e. ''not'' set or stored).
Line 104: Line 137:
Synchronous method to read a setting. An exception is raised if the key has not previously been set.

=== Notes ===

 * I decided not to include the ''version'' argument for '''!ApplyUpdate()''' and '''!CancelUpdate()'''. I understand why these were requested, but I'm calling YAGNI on it, at least for now. It complicates the API and until we work out the semantics for updating to anything other than the highest build number available, I want to keep things simple. It's easier to add things to an API than remove them. Similarly on the '''!UpdateProgress''', '''UpdateDownloaded''', and '''UpdateFailed''' signals, although not on the '''!UpdateAvailableStatus''' signal since the version there would indicate what update candidate we're going to update to. However, the etherpad indicates that this value may allow for synchronization between the u/i and the client. For example, it might allow for ignoring some signals in the case where an update is canceled and later restarted. Using a version for this isn't sufficient though because no new update may be available between these two actions. Thus for the latter use case, we may need an "update id". Still, I'd rather not add this complexity unless we absolutely need it.
 * I changed the values for ''reset_level''. It made more sense to me that level 0 was a hard reset.
 * I changed the order of some of the arguments to methods and signals.
Synchronous method to read a setting. If {{{key}}} is unknown, the empty string is returned.

'''Exit()'''<<BR>>
Synchronous method causing the client process to exit immediately. There is no return value. If this is not called, the client will still exit normally after some configurable amount of time. DBus activation will restart it.
Line 114: Line 145:

== Mock scenarios ==

=== Normal update in auto mode ===

option: --testing=update-auto-success
 1. !CheckForUpdate() is received
 2. wait for 3 seconds
 3. !UpdateAvailableStatus(is_available: true, downloading: true, available_version: 42, update_size: 1337*1024*1024, last_update_date: 1983-09-13T12:13:14, descriptions: [{'description': "Ubuntu Edge support", 'description-en_GB': 'change the background colour', 'description-fr': "Support d'Ubuntu Edge"}, {'description': "Flipped container with 200% boot speed improvement"}], error_reason: "") is sent by the daemon
 4. immediately the daemon sends !UpdateProgress(0, 50)
 5. then every half a second, send !UpdateProgress(+1, -0.5)
 6. daemon sends !UpdateDownloaded()
 7. client sends !ApplyUpdate(), daemon gives back an empty string (success)

Note that while download is in progress, calling:
 * !PauseDownload will pause the emission of !UpdateProgress(). It's a noop otherwise (even if called when not download).
 * !DownloadUpdate will resume the emission of this signal. It's a noop otherwise (even if called when not download).
 * !CancelUpdate will cancel the update. It's a noop otherwise (even if called when not download). Next !CheckForUpdate will restart from 1.
 * !CheckForUpdate will immediately resends !UpdateSignal and !UpdateProgress (if a download is in progress). Then, it will eventually send !UpdateDownload if the update was already done, as per spec.

General:
 * !GetSetting("auto_download") returns "1"
 * !SetSetting("auto_download", ''int'') will set the value in memory and then !GetSetting() will return it
 * !GetSetting("foo") returns ""

=== Normal update in manual mode ===

--testing=update-manual-success
 1. !CheckForUpdate() is received
 2. wait for 3 seconds
 3. !UpdateAvailableStatus(is_available: true, downloading: false, available_version: 42, update_size: 1337*1024*1024, last_update_date: 83-09-13, descriptions: [{'description': "Ubuntu Edge support", 'description-en_GB': 'change the background colour', 'description-fr': "Support d'Ubuntu Edge"}, {'description': "Flipped container with 200% boot speed improvement"}], error_reason: "") is sent by the daemon
 4. clients sends !DownloadUpdate
 5. immediately the daemon sends !UpdateProgress(0, 50)
 6. then every half a second, send !UpdateProgress(+1, -0.5)
 7. daemon sends !UpdateDownloaded()
 8. client sends !ApplyUpdate, daemon gives back an empty string (success)

=== Failing update ===

--testing=update-failed
The daemon is already in failure mode
 1. the client will send !CheckForUpdate
 2. the daemon answers with !UpdateAvailableStatus(is_available: true, downloading: false, available_version: 42, update_size: 1337*1024*1024, last_update_date: 83-09-13, descriptions: [{'description': "Ubuntu Edge support", 'description-en_GB': 'change the background colour', 'description-fr': "Support d'Ubuntu Edge"}, {'description': "Flipped container with 200% boot speed improvement"}], error_reason: "You need some network for downloading.")
 3. the daemon then send !UpdateFailed(9, "You need some network for downloading.")
 4. the client will then send !CancelUpdate
 5. the client will send !CheckForUpdate
 6. the daemon answers with !UpdateAvailableStatus(is_available: true, downloading: false, available_version: 42, update_size: 1337*1024*1024, last_update_date: 83-09-13, descriptions: [{'description': "Ubuntu Edge support", 'description-en_GB': 'change the background colour', 'description-fr': "Support d'Ubuntu Edge"}, {'description': "Flipped container with 200% boot speed improvement"}], error_reason: "")

=== Failing apply ===

option: --testing=fail-apply
the daemon is in !UpdateDownloaded mode
 1. the client will send !CheckForUpdate
 2. the daemon answers with !UpdateAvailableStatus(is_available: true, downloading: false, available_version: 42, update_size: 1337*1024*1024, last_update_date: 83-09-13, descriptions: [{'description': "Ubuntu Edge support", 'description-en_GB': 'change the background colour', 'description-fr': "Support d'Ubuntu Edge"}, {'description': "Flipped container with 200% boot speed improvement"}], error_reason: "")
 3. then the daemon sends the !UpdateDownloaded signal
 4. client sends !ApplyUpdate and receive "Not enough battery, you need to plug your phone." string

=== Failing Resume / Manual download ===
--testing=fail-resume
the daemon is paused, 42% of download is done
 1. the client will send !CheckForUpdate
 2. the daemon answers with !UpdateAvailableStatus(is_available: true, downloading: false, available_version: 42, update_size: 1337*1024*1024, last_update_date: 83-09-13, descriptions: [{'description': "Ubuntu Edge support", 'description-en_GB': 'change the background colour', 'description-fr': "Support d'Ubuntu Edge"}, {'description': "Flipped container with 200% boot speed improvement"}], error_reason: "")
 3. the daemons sends the !UpdatePaused(42) signal
 4. client tries to call !DownloadUpdate() and receive an !UpdateFailed(9, "You need some network for downloading.")

=== Failing pause ===
--testing=fail-pause
the daemon is downloading, initially, 10% is downloaded, there is no known ETA.
 1. the client will send !CheckForUpdate
 2. the daemon answers with !UpdateAvailableStatus(is_available: true, downloading: true, available_version: 42, update_size: 1337*1024*1024, last_update_date: '1983-09-13T12:13:14', descriptions: [{'description': "Ubuntu Edge support", 'description-en_GB': 'change the background colour', 'description-fr': "Support d'Ubuntu Edge"}, {'description': "Flipped container with 200% boot speed improvement"}], error_reason: "")
 3. immediately the daemon sends !UpdateProgress(10, 0) (note! 0 for no ETA)
 4. the clients then sends !PauseDownload() and will receive "no no, not now" as a string from the daemon.

=== No Update ===
--testing=no-update
Nothing is downloading and no check is in progress.
 1. client sends !CheckForUpdate
 2. daemon answers with !UpdateAvailableStatus(is_available: false, downlading: false, ? ?, last_update_date: '1983-09-13T12:13:14', ", ")

Client side

Introduction

The client tool is used to calculate the update, download the files, validate them and then set the needed flags for the upgrader to pick them up and apply.

Requirements

  • Secure download of the indexes (HTTPS + GPG)
  • Support for everything described in the GPG spec (revocation list, multiple keyrings, ...)

  • Resolution of the best upgrade path based on different policies (total download size, least number of reboots, ...)
  • Download and validation of the files
  • Flexible implementation to allow different upgrader setups with minimal changes required
  • Support for suspend/resume of downloads

Nice to have

  • Bandwidth limiting is a nice to have and might be tricky to implement.

Implementation

The current implementation is a command line tool, however it's expected to be turned into a DBus service that the Touch UI can drive.

Step-by-step example for an update

Whenever called the client does the following:

  1. Grab https://server/channels.json and lookup the index for the current channel. If present, also grab the device GPG keyring.

  2. Grab https://server/<channel>/<model>/index.json

  3. Read the current version number of the device (ubuntu-build file)
  4. Look for the most recent version available
  5. Resolve an upgrade path to it, minimizing download size and number of reboots
  6. Download any file needed up until the next reboot
  7. Validate all the files
  8. Write them to the cache partition
  9. Write the list of updates for the upgrader to use
  10. Reboot into the upgrader

Those steps don't include all of the specific GPG validation bits required to ensure the authenticity of all files. Those are detailed in the separate GPG wiki page.

Security (e.g. what to download over https/http) is outlined in the server security section.

DBus API

The client will export a DBus API on the system bus which will allow for a u/i in the System Settings to query, begin, cancel, and apply a system update. This service starts via DBus activation and exits automatically after a configurable amount of time (i.e. it does not run forever). It maintains state such that the client can exit and get restarted to continue the update, even across reboots. The client uses the download service to manage all file downloads. Here is the DBus API specification:

Signals

UpdateAvailableStatus(is_available, downloading, available_version, update_size, last_update_date, descriptions, error_reason)
Sent in response to CheckForUpdate() async calls, this signal provides information about the state of the update.

  • is_available - boolean which indicates whether an update is available or not. This will be false if the device's build number is equal to or greater than any candidate build on the server (IOW, there is no candidate available). This flag will be true when there is an update available.

  • downloading - boolean indicating whether a download is in progress. This doesn't include any preliminary downloads needed to determine whether a candidate is available or not (e.g. keyrings, blacklists, channels.json, and index.json files). This flag will be false if a download is paused.

  • available_version - string specifying the update target candidate version.

  • update_size - integer providing total size in bytes for an available upgrade. This does not include any preliminary files needed to determine whether an update is available or not.

  • last_update_date - the ISO 8601 format UTC date (to the second) that the last update was applied to this device. This will be the empty string if no update has been previously applied.

  • descriptions - array of mappings containing the descriptions for all updates that will be downloaded. Each element of the array is a mapping of language-specific description keys to the UTF-8 description for that language. See the server documentation for details.

  • error_reason - A UTF-8 English human readable string indicating why the download did not start. Only useful if the second argument (downloading) is false, otherwise ignore this value.

Depending on the state of the system, as described below, some of the arguments of this signal may be ignored.

UpdateProgress(percentage, eta)
Sent periodically, while a download is in progress. This signal is not sent when an upgrade is paused.

  • percentage - integer between 0 and 100 indicating how much of the download (not including preliminary files) have been currently downloaded. This may be 0 if we do not yet know what percentage has been downloaded.

  • eta - estimated time remaining to complete the download, in float seconds. This may be 0 if we don't have a reasonable estimate.

UpdatePaused(percentage)
Sent whenever a download is paused as detected via the download service.

  • percentage - integer between 0 and 100 indicating how much of the download (not including preliminary files) have been currently downloaded. May be 0 if this information cannot be obtained.

UpdateDownloaded()
Sent when the currently in progress update has been completely and successfully downloaded. When this signal is received, it means that the device is ready to have the update applied via ApplyUpdate().

UpdateFailed(consecutive_failure_count, last_reason)
Sent when the update failed for any reason (including cancellation, but only if a download is in progress). The client will remain in the failure state until the next CheckForUpdate() call.

  • consecutive_failure_count - an integer specifying the number of times in a row that a CheckForUpdate() has resulted in an update failure. This increments until an update completes successfully (i.e. until the next UpdateDownloaded() signal is issued).

  • last_reason - a UTF-8 string containing the English reason for why this updated failed.

Rebooting(status)
Sent just before the device reboots.

  • status - a boolean indicating whether the application of the update is successful or not. Generally, when status is true you won't ever receive the signal because the device will reboot. When status is false it means the application of the update or reboot failed for some reason.

SettingChanged(key, value)
Sent when a setting is changed. This signal is not sent if the new value is the same as the old value.

  • key - the key of the value that was changed.

  • value - the new value for the key.

Methods

CheckForUpdate()
Asynchronous call instructing the client to check for an available update. If a check is already in progress, it continues. If the client is in auto-download mode (see below), then this call will both check the server for an available update, and automatically initiate the download of an available update. If the client is in manual-download mode, then the downloading of any available update will not occur automatically (use DownloadUpdate() explicitly to start the download). It is also possible for the download to only occur automatically if other criteria are met, e.g. we are not on a wifi, or the device has a low battery. Note that CheckForUpdate() will never resume a download.

In all cases, an UpdateAvailableStatus signal will be issued once an update candidate is determined to be available; the arguments can have the following values:

  • UpdateAvailableStatus(true, true, build_number, size, "YYYY-MM-DDTHH:MM:SS", descriptions, "") - This means that an update is available and is currently downloading. The build number of the candidate update is given, as is its total size in bytes, and the descriptions of the updates in all available languages.

  • UpdateAvailableStatus(true, false, build_number, size, "YYYY-MM-DDTHH:MM:SS", descriptions, "paused") - This means that an update is available, but it is not yet downloading, possibly because the client is in manual-update mode, or because the download is currently paused. The reason is given in the last argument, and the build number, size, and descriptions are given as above.

  • UpdateAvailableStatus(false, ?, ?, ?, "YYYY-MM-DDTHH:MM:SS", ?, ?) - There is no update available. The ISO 8601 date of the last applied update is given, but all other arguments should be ignored.

If we are in auto-download mode, an UpdateProgress() signal is sent as soon as the download is started, usually with a percentage of 0 and an eta of 0.

DownloadUpdate()
Asynchronous method to download an available update. No-ops if there is no update to download, an automatic download is already in progress, CheckForUpdate() was not called first, or the update status is in an error condition. If a previous download was paused, this resumes the download. As with auto-download mode, an UpdateProgress() signal is sent as soon as the download is started.

ApplyUpdate()
Asynchronous method to apply the update and initiate the reboot. No-ops if no new update has been downloaded. Because the success path leads almost immediately to a reboot, this method does not return anything, but a Rebooting signal is sent.

CancelUpdate()
Synchronous method to cancel any update check or download (even finished or paused) in progress. The empty string is returned unless an error occurred, in which case the error message is returned as a UTF-8 English string.

PauseDownload()
Synchronous method to pause the current download. The empty string is returned unless an error occurred, in which case the error message is returned as a UTF-8 English string.

Info()
Get information about the system images, similar to what is available via system-image-cli --info. Returns the following pieces of information.

  • current build number - integer

  • device name - string

  • channel name - string

  • last update date - ISO 8601 UTC format string, with second resolution, e.g. "YYYY-MM-DDTHH:MM:SS"

  • version details - dictionary of strings-to-strings where the keys are component names and the values are version strings.

Info2()
Like Info(), but returns extended information that includes the last time a CheckForUpdate() was performed. Returns the following pieces of information.

  • current build number - integer

  • device name - string

  • channel name - string

  • last update date - ISO 8601 UTC format string, with second resolution, e.g. "YYYY-MM-DDTHH:MM:SS"

  • version details - dictionary of strings-to-strings where the keys are component names and the values are version strings.

  • last check date - ISO 8601 UTC format string, with second resolution, e.g. "YYYY-MM-DDTHH:MM:SS"

FactoryReset()
Wipe the data partition and issue a reboot to recovery. Takes no arguments, but possibly sends a Rebooting() signal (depending on the race against the system reboot procedure). New in system-image 2.3.

SetSetting(key, value)
Synchronous method to write or update a setting. key and value are UTF-8 strings. While any key/value pair may be set, only the following currently have useful semantics:

  • min_battery - The minimum battery strength which will allow downloads to proceed. The value is the string representation of a number between 0 and 100 percent. If the battery level is less than this, an available download will not be automatically initiated, although an explicit DownloadUpdate() call can force this.

  • auto_download - A tri-state (currently) value indicating whether downloads should normally proceed automatically if an update is available or not. The value is the string representation of the following integer values.

    • 0 - Never download automatically (i.e. an explicit DownloadUpdate() call is required to start the download)

    • 1 - Only auto-download if the device is connected via wifi (the default)
    • 2 - Always download the update automatically
  • failures_before_warning - Unused by the client, but stored here for use by the user interface.

If the new value is different than the old value, or if this key was not previously set, a SettingChanged(key, value) signal is sent.

For the values with semantics, any invalid value is ignored (i.e. not set or stored).

GetSetting(key)
Synchronous method to read a setting. If key is unknown, the empty string is returned.

Exit()
Synchronous method causing the client process to exit immediately. There is no return value. If this is not called, the client will still exit normally after some configurable amount of time. DBus activation will restart it.

Code

Mock scenarios

Normal update in auto mode

option: --testing=update-auto-success

  1. CheckForUpdate() is received

  2. wait for 3 seconds
  3. UpdateAvailableStatus(is_available: true, downloading: true, available_version: 42, update_size: 1337*1024*1024, last_update_date: 1983-09-13T12:13:14, descriptions: [{'description': "Ubuntu Edge support", 'description-en_GB': 'change the background colour', 'description-fr': "Support d'Ubuntu Edge"}, {'description': "Flipped container with 200% boot speed improvement"}], error_reason: "") is sent by the daemon

  4. immediately the daemon sends UpdateProgress(0, 50)

  5. then every half a second, send UpdateProgress(+1, -0.5)

  6. daemon sends UpdateDownloaded()

  7. client sends ApplyUpdate(), daemon gives back an empty string (success)

Note that while download is in progress, calling:

  • PauseDownload will pause the emission of UpdateProgress(). It's a noop otherwise (even if called when not download).

  • DownloadUpdate will resume the emission of this signal. It's a noop otherwise (even if called when not download).

  • CancelUpdate will cancel the update. It's a noop otherwise (even if called when not download). Next CheckForUpdate will restart from 1.

  • CheckForUpdate will immediately resends UpdateSignal and UpdateProgress (if a download is in progress). Then, it will eventually send UpdateDownload if the update was already done, as per spec.

General:

  • GetSetting("auto_download") returns "1"

  • SetSetting("auto_download", int) will set the value in memory and then GetSetting() will return it

  • GetSetting("foo") returns ""

Normal update in manual mode

--testing=update-manual-success

  1. CheckForUpdate() is received

  2. wait for 3 seconds
  3. UpdateAvailableStatus(is_available: true, downloading: false, available_version: 42, update_size: 1337*1024*1024, last_update_date: 83-09-13, descriptions: [{'description': "Ubuntu Edge support", 'description-en_GB': 'change the background colour', 'description-fr': "Support d'Ubuntu Edge"}, {'description': "Flipped container with 200% boot speed improvement"}], error_reason: "") is sent by the daemon

  4. clients sends DownloadUpdate

  5. immediately the daemon sends UpdateProgress(0, 50)

  6. then every half a second, send UpdateProgress(+1, -0.5)

  7. daemon sends UpdateDownloaded()

  8. client sends ApplyUpdate, daemon gives back an empty string (success)

Failing update

--testing=update-failed The daemon is already in failure mode

  1. the client will send CheckForUpdate

  2. the daemon answers with UpdateAvailableStatus(is_available: true, downloading: false, available_version: 42, update_size: 1337*1024*1024, last_update_date: 83-09-13, descriptions: [{'description': "Ubuntu Edge support", 'description-en_GB': 'change the background colour', 'description-fr': "Support d'Ubuntu Edge"}, {'description': "Flipped container with 200% boot speed improvement"}], error_reason: "You need some network for downloading.")

  3. the daemon then send UpdateFailed(9, "You need some network for downloading.")

  4. the client will then send CancelUpdate

  5. the client will send CheckForUpdate

  6. the daemon answers with UpdateAvailableStatus(is_available: true, downloading: false, available_version: 42, update_size: 1337*1024*1024, last_update_date: 83-09-13, descriptions: [{'description': "Ubuntu Edge support", 'description-en_GB': 'change the background colour', 'description-fr': "Support d'Ubuntu Edge"}, {'description': "Flipped container with 200% boot speed improvement"}], error_reason: "")

Failing apply

option: --testing=fail-apply the daemon is in UpdateDownloaded mode

  1. the client will send CheckForUpdate

  2. the daemon answers with UpdateAvailableStatus(is_available: true, downloading: false, available_version: 42, update_size: 1337*1024*1024, last_update_date: 83-09-13, descriptions: [{'description': "Ubuntu Edge support", 'description-en_GB': 'change the background colour', 'description-fr': "Support d'Ubuntu Edge"}, {'description': "Flipped container with 200% boot speed improvement"}], error_reason: "")

  3. then the daemon sends the UpdateDownloaded signal

  4. client sends ApplyUpdate and receive "Not enough battery, you need to plug your phone." string

Failing Resume / Manual download

--testing=fail-resume the daemon is paused, 42% of download is done

  1. the client will send CheckForUpdate

  2. the daemon answers with UpdateAvailableStatus(is_available: true, downloading: false, available_version: 42, update_size: 1337*1024*1024, last_update_date: 83-09-13, descriptions: [{'description': "Ubuntu Edge support", 'description-en_GB': 'change the background colour', 'description-fr': "Support d'Ubuntu Edge"}, {'description': "Flipped container with 200% boot speed improvement"}], error_reason: "")

  3. the daemons sends the UpdatePaused(42) signal

  4. client tries to call DownloadUpdate() and receive an UpdateFailed(9, "You need some network for downloading.")

Failing pause

--testing=fail-pause the daemon is downloading, initially, 10% is downloaded, there is no known ETA.

  1. the client will send CheckForUpdate

  2. the daemon answers with UpdateAvailableStatus(is_available: true, downloading: true, available_version: 42, update_size: 1337*1024*1024, last_update_date: '1983-09-13T12:13:14', descriptions: [{'description': "Ubuntu Edge support", 'description-en_GB': 'change the background colour', 'description-fr': "Support d'Ubuntu Edge"}, {'description': "Flipped container with 200% boot speed improvement"}], error_reason: "")

  3. immediately the daemon sends UpdateProgress(10, 0) (note! 0 for no ETA)

  4. the clients then sends PauseDownload() and will receive "no no, not now" as a string from the daemon.

No Update

--testing=no-update Nothing is downloading and no check is in progress.

  1. client sends CheckForUpdate

  2. daemon answers with UpdateAvailableStatus(is_available: false, downlading: false, ? ?, last_update_date: '1983-09-13T12:13:14', ", ")

ImageBasedUpgrades/Client (last edited 2016-10-31 14:09:03 by localhost)