Azure/iot-hub-device-update

Proxy update with reboot: update restarts instead of continuing

Closed this issue · 2 comments

We're planning to use Device Update for IoT Hub for an embedded device (ARM) which is running a custom-built Linux.

To evaluate the build, deployment, and operation of the device update agent, I've created a "manual" build of DUA 1.1.0 in a Debian 11 VM. I.e. I did not use apt packages for the installation, but I built the device agent in the VM (including its dependencies).

As we're planning to use proxy updates I've written

  • a custom component enumerator,
  • a custom flash update handler,
  • and a custom child device update handler.

The update package contains 6 steps

  • Step 1: The flashing of the main device firmware.
  • Steps 2 to 6: Storing update packages for child devices (which can become active at a later point and will get updated then).

After step 1 a reboot is required, because it's an A/B update and we have to switch slots.

The custom flash update handler requests a reboot after the install step by calling workflow_request_immediate_reboot(workflowData->WorkflowHandle);

Setting the return value of
ADUC_Result flash_update_handler::Install([[maybe_unused]]const tagADUC_WorkflowData* workflowData);
to
ADUC_Result_Install_RequiredImmediateReboot
doesn't seem to be enough and doesn't trigger a reboot.
I find this weird because I have to implement an interface, but the correct behavior of the extension relies on side effects and not just the contract defined by the interface. But that's a different story.

Unfortunately, the reboot seems to interrupt the logging. The last line I see in the journal is

Jul 31 12:01:25 AducIotAgent[2571]: 2024-07-31T10:01:25.4072Z 2571[2589] [I] Loading extension 'foo/flash:1'. Reg file : /var/lib/adu/extensions/update_content_handlers/foo_flash_1/content_handler.json [LoadExtensionLibrary:85]

So I'm not quite sure what happens after the install step and before rebooting.

After the VM reboots the DUA restarts. But it doesn't seem to continue the update where it left off, but restarts enumerating all components again and checks if they are installed.
Now, step 0 (the flashed component) reports that it is already installed. The other components of course do not and thus get installed.
In the end, all components are updated.

In the device twin, the device now reports that it is updated to the latest version:

{
	"__t": "c",
	"agent": {
		"deviceProperties": {
			"manufacturer": "foo",
			"model": "bar",
			"contractModelId": "dtmi:azure:iot:deviceUpdateContractModel;3",
			"aduVer": "DU;agent/1.1.0"
		},
		"compatPropertyNames": "manufacturer,model",
		"lastInstallResult": {
			"resultCode": 700,
			"extendedResultCodes": "00000000,A0000FFF",
			"stepResults": {
				"step_0": {
					"resultCode": 603,
					"extendedResultCodes": "00000000",
					"resultDetails": ""
				},
				"step_1": {
					"resultCode": 700,
					"extendedResultCodes": "00000000",
					"resultDetails": ""
				},
				"step_2": {
					"resultCode": 700,
					"extendedResultCodes": "00000000",
					"resultDetails": ""
				},
				"step_3": {
					"resultCode": 700,
					"extendedResultCodes": "00000000",
					"resultDetails": ""
				},
				"step_4": {
					"resultCode": 700,
					"extendedResultCodes": "00000000",
					"resultDetails": ""
				},
				"step_5": {
					"resultCode": 700,
					"extendedResultCodes": "00000000",
					"resultDetails": ""
				}
			},
			"resultDetails": ""
		},
		"state": 0,
		"workflow": {
			"action": 3,
			"id": "f64ab3bb-8796-4ea4-b993-9a559ef7d1c9"
		},
		"installedUpdateId": "{\"provider\":\"foo\",\"name\":\"bar\",\"version\":\"17.0.0.1\"}"
	}
}

The state of the device is correct now, but the ugly thing is, that step_0's resultCode is 603 (already installed). The reason for this is, that the update restarted and did not continue.

Is this normal/expected behavior or am I doing something wrong? E.g. in the custom flash extension or the DUA configuration.

@D-r-P-3-p-p-3-r , first, thank you for your feedback and detailed information.

If the step_0 resultCode is 603 (already installed), this probably mean that the 'Is_Installed' logic for the step_0, returned '900' (ADUC_Result_IsInstalled_Installed). Please double check your logic in IsInstalled function.

If you need to perform additional tasks (in step_0) after the firmware has been updated, and device rebooted, you should make sure that the IsInstalled doesn't return 900 until all tasks has been completed successfully.

Please let me know

The component is already completely installed after the reboot (in the new slot). So isInstalled should and does return 900. I was just surprised that in stepResults it shows 603.
After the reboot this interpretation is correct. Looking at the complete update (including the update part before the restart) this status seems weird/surprising. For somebody looking at this naively (like me), it looks like the component was up-to-date all along. Which it wasn’t. It wasn’t installed as the update started.
But after checking the DUA code this seems to be the way things are implemented. I guess it's a drawback stemming from the design choice only to update the twin at the very end of the update.