Integrate update agent interface

Access existing update agent implementation via and update agent
interface. Align tests and deployments to use the new initialization
methods.

Signed-off-by: Imre Kis <imre.kis@arm.com>
Change-Id: I31d501fc6601be6d396ef38ef65c500ba8acdec4
diff --git a/components/app/fwu-tool/app/fwu_app.cpp b/components/app/fwu-tool/app/fwu_app.cpp
index 173afce..9613e73 100644
--- a/components/app/fwu-tool/app/fwu_app.cpp
+++ b/components/app/fwu-tool/app/fwu_app.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2023-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -31,13 +31,12 @@
 	: m_update_agent()
 	, m_fw_store()
 {
-	memset(&m_update_agent, 0, sizeof(m_update_agent));
 	memset(&m_fw_store, 0, sizeof(m_fw_store));
 }
 
 fwu_app::~fwu_app()
 {
-	update_agent_deinit(&m_update_agent);
+	update_agent_deinit(m_update_agent);
 	banked_fw_store_deinit(&m_fw_store);
 
 	fwu_deconfigure();
@@ -96,10 +95,9 @@
 		return -1;
 	}
 
-	status = update_agent_init(&m_update_agent, boot_index, direct_fw_inspector_inspect,
-				   &m_fw_store);
+	m_update_agent = update_agent_init(boot_index, direct_fw_inspector_inspect, &m_fw_store);
 
-	if (status) {
+	if (!m_update_agent) {
 		IMSG("update agent initialisation error %d", status);
 		return -1;
 	}
@@ -111,27 +109,31 @@
 int fwu_app::update_image(const struct uuid_octets &img_type_uuid, const uint8_t *img_data,
 			  size_t img_size)
 {
-	int status = update_agent_begin_staging(&m_update_agent);
+	int status = update_agent_begin_staging(m_update_agent, 0, 0, NULL);
 
 	if (status)
 		return status;
 
 	uint32_t stream_handle = 0;
+	uint32_t progress = 0;
+	uint32_t total_work = 0;
 
-	status = update_agent_open(&m_update_agent, &img_type_uuid, &stream_handle);
+	status = update_agent_open(m_update_agent, &img_type_uuid, FWU_OP_TYPE_WRITE,
+				   &stream_handle);
 
 	if (!status) {
-		status = update_agent_write_stream(&m_update_agent, stream_handle, img_data,
+		status = update_agent_write_stream(m_update_agent, stream_handle, img_data,
 						   img_size);
 
 		if (!status)
-			status = update_agent_commit(&m_update_agent, stream_handle, false);
+			status = update_agent_commit(m_update_agent, stream_handle, false, 0,
+						     &progress, &total_work);
 	}
 
 	if (!status)
-		status = update_agent_end_staging(&m_update_agent);
+		status = update_agent_end_staging(m_update_agent);
 	else
-		update_agent_cancel_staging(&m_update_agent);
+		update_agent_cancel_staging(m_update_agent);
 
 	return status;
 }
@@ -139,7 +141,8 @@
 int fwu_app::read_object(const struct uuid_octets &object_uuid, std::vector<uint8_t> &data)
 {
 	uint32_t stream_handle = 0;
-	int status = update_agent_open(&m_update_agent, &object_uuid, &stream_handle);
+	int status = update_agent_open(m_update_agent, &object_uuid, FWU_OP_TYPE_READ,
+				       &stream_handle);
 
 	if (status)
 		return status;
@@ -150,6 +153,8 @@
 	size_t reported_total_len = 0;
 	size_t read_so_far = 0;
 	size_t vector_capacity = 512;
+	uint32_t progress = 0;
+	uint32_t total_work = 0;
 
 	data.resize(vector_capacity);
 
@@ -157,7 +162,7 @@
 		size_t data_len_read = 0;
 		size_t requested_read_len = vector_capacity - read_so_far;
 
-		status = update_agent_read_stream(&m_update_agent, stream_handle,
+		status = update_agent_read_stream(m_update_agent, stream_handle,
 						  &data[read_so_far], requested_read_len,
 						  &data_len_read, &reported_total_len);
 
@@ -181,14 +186,15 @@
 
 	} while (!status);
 
-	status = update_agent_commit(&m_update_agent, stream_handle, false);
+	status = update_agent_commit(m_update_agent, stream_handle, false, 0, &progress,
+				     &total_work);
 
 	return status;
 }
 
 struct update_agent *fwu_app::update_agent()
 {
-	return &m_update_agent;
+	return m_update_agent;
 }
 
 const struct metadata_serializer *fwu_app::select_metadata_serializer(unsigned int version)
diff --git a/components/app/fwu-tool/app/fwu_app.h b/components/app/fwu-tool/app/fwu_app.h
index 8bbaa9d..c60f192 100644
--- a/components/app/fwu-tool/app/fwu_app.h
+++ b/components/app/fwu-tool/app/fwu_app.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2023-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -11,7 +11,7 @@
 #include <vector>
 
 #include "common/uuid/uuid.h"
-#include "service/fwu/agent/update_agent.h"
+#include "service/fwu/common/update_agent_interface.h"
 #include "service/fwu/fw_store/banked/banked_fw_store.h"
 
 /*
@@ -98,7 +98,7 @@
 
 	static const struct metadata_serializer *select_metadata_serializer(unsigned int version);
 
-	struct update_agent m_update_agent;
+	struct update_agent *m_update_agent;
 	struct fw_store m_fw_store;
 };
 
diff --git a/components/service/fwu/agent/update_agent.c b/components/service/fwu/agent/update_agent.c
index 2a4d19d..77037b1 100644
--- a/components/service/fwu/agent/update_agent.c
+++ b/components/service/fwu/agent/update_agent.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022, Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -17,80 +17,51 @@
 #include "protocols/service/fwu/packed-c/status.h"
 #include "service/fwu/fw_store/fw_store.h"
 #include "service/fwu/inspector/fw_inspector.h"
+#include "trace.h"
 
-static bool open_image_directory(struct update_agent *update_agent, const struct uuid_octets *uuid,
-				 uint32_t *handle, int *status);
+/**
+ * \brief Update process states
+ *
+ * The update_agent is responsible for ensuring that only a valid update flow
+ * is followed by a client. To enforce the flow, public operations can only be
+ * used in a valid state that reflects the FWU-A behavioral model.
+ */
+enum fwu_state {
+	FWU_STATE_DEINITIALZED,
+	FWU_STATE_INITIALIZING,
+	FWU_STATE_REGULAR,
+	FWU_STATE_STAGING,
+	FWU_STATE_TRIAL_PENDING,
+	FWU_STATE_TRIAL
+};
 
-static bool open_fw_store_object(struct update_agent *update_agent, const struct uuid_octets *uuid,
-				 uint32_t *handle, int *status);
+/**
+ * \brief update_agent structure definition
+ *
+ * An update_agent instance is responsible for coordinating firmware updates applied
+ * to a fw_store. An update_agent performs a security role by enforcing that a
+ * valid flow is performed to update the fw store.
+ */
+struct generic_update_agent {
+	enum fwu_state state;
+	fw_inspector_inspect fw_inspect_method;
+	struct fw_store *fw_store;
+	struct fw_directory fw_directory;
+	struct stream_manager stream_manager;
+	uint8_t *image_dir_buf;
+	size_t image_dir_buf_size;
+};
 
-static bool open_fw_image(struct update_agent *update_agent, const struct uuid_octets *uuid,
-			  uint32_t *handle, int *status);
+static int cancel_staging(void *context);
 
-int update_agent_init(struct update_agent *update_agent, unsigned int boot_index,
-		      fw_inspector_inspect fw_inspect_method, struct fw_store *fw_store)
-{
-	assert(update_agent);
-	assert(fw_inspect_method);
-	assert(fw_store);
-
-	int status = FWU_STATUS_UNKNOWN;
-
-	update_agent->state = FWU_STATE_INITIALIZING;
-	update_agent->fw_inspect_method = fw_inspect_method;
-	update_agent->fw_store = fw_store;
-	update_agent->image_dir_buf_size = 0;
-	update_agent->image_dir_buf = NULL;
-
-	stream_manager_init(&update_agent->stream_manager);
-
-	/* Initialize and populate the fw_directory. The fw_inspector will
-	 * obtain trustworthy information about the booted firmware and
-	 * populate the fw_directory to reflect information about the booted
-	 * firmware.
-	 */
-	fw_directory_init(&update_agent->fw_directory);
-
-	status = update_agent->fw_inspect_method(&update_agent->fw_directory, boot_index);
-	if (status != FWU_STATUS_SUCCESS)
-		return status;
-
-	/* Allow the associated fw_store to synchronize its state to the
-	 * state of the booted firmware reflected by the fw_directory.
-	 */
-	status = fw_store_synchronize(update_agent->fw_store, &update_agent->fw_directory,
-				      boot_index);
-	if (status != FWU_STATUS_SUCCESS)
-		return status;
-
-	/* Allocate a buffer for holding the serialized image directory  */
-	update_agent->image_dir_buf_size = img_dir_serializer_get_len(&update_agent->fw_directory);
-	update_agent->image_dir_buf = malloc(update_agent->image_dir_buf_size);
-	if (!update_agent->image_dir_buf)
-		return FWU_STATUS_UNKNOWN;
-
-	/* Transition to initial state */
-	update_agent->state = fw_store_is_trial(update_agent->fw_store) ? FWU_STATE_TRIAL :
-									  FWU_STATE_REGULAR;
-
-	return FWU_STATUS_SUCCESS;
-}
-
-void update_agent_deinit(struct update_agent *update_agent)
-{
-	update_agent->state = FWU_STATE_DEINITIALZED;
-
-	free(update_agent->image_dir_buf);
-	fw_directory_deinit(&update_agent->fw_directory);
-	stream_manager_deinit(&update_agent->stream_manager);
-}
-
-int update_agent_begin_staging(struct update_agent *update_agent)
+static int begin_staging(void *context, uint32_t vendor_flags, uint32_t partial_update_count,
+			 const struct uuid_octets *update_guid)
 {
 	int status = FWU_STATUS_DENIED;
+	struct generic_update_agent *update_agent = (struct generic_update_agent *)context;
 
 	/* If already staging, any previous installation state is discarded */
-	update_agent_cancel_staging(update_agent);
+	cancel_staging(update_agent);
 
 	if (update_agent->state == FWU_STATE_REGULAR) {
 		status = fw_store_begin_install(update_agent->fw_store);
@@ -103,9 +74,10 @@
 	return status;
 }
 
-int update_agent_end_staging(struct update_agent *update_agent)
+static int end_staging(void *context)
 {
 	int status = FWU_STATUS_DENIED;
+	struct generic_update_agent *update_agent = (struct generic_update_agent *)context;
 
 	if (update_agent->state == FWU_STATE_STAGING) {
 		/* The client is responsible for committing each installed image. If any
@@ -135,9 +107,10 @@
 	return status;
 }
 
-int update_agent_cancel_staging(struct update_agent *update_agent)
+static int cancel_staging(void *context)
 {
 	int status = FWU_STATUS_DENIED;
+	struct generic_update_agent *update_agent = (struct generic_update_agent *)context;
 
 	if (update_agent->state == FWU_STATE_STAGING) {
 		stream_manager_cancel_streams(&update_agent->stream_manager,
@@ -153,10 +126,10 @@
 	return status;
 }
 
-int update_agent_accept(struct update_agent *update_agent,
-			const struct uuid_octets *image_type_uuid)
+static int accept(void *context, const struct uuid_octets *image_type_uuid)
 {
 	int status = FWU_STATUS_DENIED;
+	struct generic_update_agent *update_agent = (struct generic_update_agent *)context;
 
 	if (update_agent->state == FWU_STATE_TRIAL) {
 		const struct image_info *image_info =
@@ -181,9 +154,10 @@
 	return status;
 }
 
-int update_agent_select_previous(struct update_agent *update_agent)
+static int select_previous(void *context)
 {
 	int status = FWU_STATUS_DENIED;
+	struct generic_update_agent *update_agent = (struct generic_update_agent *)context;
 
 	if ((update_agent->state == FWU_STATE_TRIAL) ||
 	    (update_agent->state == FWU_STATE_TRIAL_PENDING)) {
@@ -194,42 +168,8 @@
 	return status;
 }
 
-int update_agent_open(struct update_agent *update_agent, const struct uuid_octets *uuid,
-		      uint32_t *handle)
-{
-	int status;
-
-	/* Pass UUID along a chain-of-responsibility until it's handled */
-	if (!open_image_directory(update_agent, uuid, handle, &status) &&
-	    !open_fw_store_object(update_agent, uuid, handle, &status) &&
-	    !open_fw_image(update_agent, uuid, handle, &status)) {
-		/* UUID not recognised */
-		status = FWU_STATUS_UNKNOWN;
-	}
-
-	return status;
-}
-
-int update_agent_commit(struct update_agent *update_agent, uint32_t handle, bool accepted)
-{
-	return stream_manager_close(&update_agent->stream_manager, handle, accepted);
-}
-
-int update_agent_write_stream(struct update_agent *update_agent, uint32_t handle,
-			      const uint8_t *data, size_t data_len)
-{
-	return stream_manager_write(&update_agent->stream_manager, handle, data, data_len);
-}
-
-int update_agent_read_stream(struct update_agent *update_agent, uint32_t handle, uint8_t *buf,
-			     size_t buf_size, size_t *read_len, size_t *total_len)
-{
-	return stream_manager_read(&update_agent->stream_manager, handle, buf, buf_size, read_len,
-				   total_len);
-}
-
-static bool open_image_directory(struct update_agent *update_agent, const struct uuid_octets *uuid,
-				 uint32_t *handle, int *status)
+static bool open_image_directory(struct generic_update_agent *update_agent,
+				 const struct uuid_octets *uuid, uint32_t *handle, int *status)
 {
 	struct uuid_octets target_uuid;
 
@@ -257,8 +197,8 @@
 	return false;
 }
 
-static bool open_fw_store_object(struct update_agent *update_agent, const struct uuid_octets *uuid,
-				 uint32_t *handle, int *status)
+static bool open_fw_store_object(struct generic_update_agent *update_agent,
+				 const struct uuid_octets *uuid, uint32_t *handle, int *status)
 {
 	const uint8_t *exported_data;
 	size_t exported_data_len;
@@ -277,7 +217,7 @@
 	return false;
 }
 
-static bool open_fw_image(struct update_agent *update_agent, const struct uuid_octets *uuid,
+static bool open_fw_image(struct generic_update_agent *update_agent, const struct uuid_octets *uuid,
 			  uint32_t *handle, int *status)
 {
 	const struct image_info *image_info =
@@ -305,3 +245,160 @@
 
 	return false;
 }
+
+static int open(void *context, const struct uuid_octets *uuid, uint8_t op_type, uint32_t *handle)
+{
+	int status = FWU_STATUS_SUCCESS;
+	struct generic_update_agent *update_agent = (struct generic_update_agent *)context;
+
+	/* Pass UUID along a chain-of-responsibility until it's handled */
+	if (!open_image_directory(update_agent, uuid, handle, &status) &&
+	    !open_fw_store_object(update_agent, uuid, handle, &status) &&
+	    !open_fw_image(update_agent, uuid, handle, &status)) {
+		/* UUID not recognised */
+		status = FWU_STATUS_UNKNOWN;
+	}
+
+	return status;
+}
+
+static int commit(void *context, uint32_t handle, bool accepted, uint32_t max_atomic_len,
+		  uint32_t *progress, uint32_t *total_work)
+{
+	struct generic_update_agent *update_agent = (struct generic_update_agent *)context;
+	int result = 0;
+
+	result = stream_manager_close(&update_agent->stream_manager, handle, accepted);
+	if (!result)
+		*progress = 1;
+
+	*total_work = 1;
+
+	return result;
+}
+
+static int write_stream(void *context, uint32_t handle, const uint8_t *data, size_t data_len)
+{
+	struct generic_update_agent *update_agent = (struct generic_update_agent *)context;
+
+	return stream_manager_write(&update_agent->stream_manager, handle, data, data_len);
+}
+
+static int read_stream(void *context, uint32_t handle, uint8_t *buf, size_t buf_size,
+		       size_t *read_len, size_t *total_len)
+{
+	struct generic_update_agent *update_agent = (struct generic_update_agent *)context;
+
+	return stream_manager_read(&update_agent->stream_manager, handle, buf, buf_size, read_len,
+				   total_len);
+}
+
+
+static const struct update_agent_interface interface = {
+	.discover = NULL,
+	.begin_staging = begin_staging,
+	.end_staging = end_staging,
+	.cancel_staging = cancel_staging,
+	.open = open,
+	.write_stream = write_stream,
+	.read_stream = read_stream,
+	.commit = commit,
+	.accept_image = accept,
+	.select_previous = select_previous,
+};
+
+static void deinit_context(struct generic_update_agent *context)
+{
+	if (!context)
+		return;
+
+	stream_manager_deinit(&context->stream_manager);
+	fw_directory_deinit(&context->fw_directory);
+
+	if (context->image_dir_buf)
+		free(context->image_dir_buf);
+
+	free(context);
+}
+
+struct update_agent *update_agent_init(unsigned int boot_index,
+				       fw_inspector_inspect fw_inspect_method,
+				       struct fw_store *fw_store)
+{
+	int status = FWU_STATUS_UNKNOWN;
+	struct generic_update_agent *context = NULL;
+	struct update_agent *agent = NULL;
+
+	assert(fw_inspect_method);
+	assert(fw_store);
+
+	context = (struct generic_update_agent *)calloc(1, sizeof(*context));
+	if (!context) {
+		DMSG("Failed to allocate update agent context");
+		return NULL;
+	}
+
+	context->state = FWU_STATE_INITIALIZING;
+	context->fw_inspect_method = fw_inspect_method;
+	context->fw_store = fw_store;
+	context->image_dir_buf_size = 0;
+	context->image_dir_buf = NULL;
+
+	stream_manager_init(&context->stream_manager);
+
+	/* Initialize and populate the fw_directory. The fw_inspector will
+	 * obtain trustworthy information about the booted firmware and
+	 * populate the fw_directory to reflect information about the booted
+	 * firmware.
+	 */
+	fw_directory_init(&context->fw_directory);
+
+	status = context->fw_inspect_method(&context->fw_directory, boot_index);
+	if (status != FWU_STATUS_SUCCESS) {
+		DMSG("Failed to run FW inspect: %d", status);
+		deinit_context(context);
+		return NULL;
+	}
+
+	/* Allow the associated fw_store to synchronize its state to the
+	 * state of the booted firmware reflected by the fw_directory.
+	 */
+	status = fw_store_synchronize(context->fw_store, &context->fw_directory, boot_index);
+	if (status != FWU_STATUS_SUCCESS) {
+		DMSG("Failed synchronize FW store: %d", status);
+		deinit_context(context);
+		return NULL;
+	}
+
+	/* Allocate a buffer for holding the serialized image directory  */
+	context->image_dir_buf_size = img_dir_serializer_get_len(&context->fw_directory);
+	context->image_dir_buf = malloc(context->image_dir_buf_size);
+	if (!context->image_dir_buf) {
+		DMSG("Failed to allocate image_dir_buf");
+		deinit_context(context);
+		return NULL;
+	}
+
+	/* Transition to initial state */
+	context->state = fw_store_is_trial(context->fw_store) ? FWU_STATE_TRIAL : FWU_STATE_REGULAR;
+
+	agent = (struct update_agent *)calloc(1, sizeof(*agent));
+	if (!agent) {
+		DMSG("Failed to allocate update_agent");
+		deinit_context(context);
+		return NULL;
+	}
+
+	agent->context = context;
+	agent->interface = &interface;
+
+	return agent;
+}
+
+void update_agent_deinit(struct update_agent *update_agent)
+{
+	struct generic_update_agent *context = (struct generic_update_agent *)update_agent->context;
+
+	deinit_context(context);
+	free(update_agent);
+}
diff --git a/components/service/fwu/agent/update_agent.h b/components/service/fwu/agent/update_agent.h
index ea214ee..9004252 100644
--- a/components/service/fwu/agent/update_agent.h
+++ b/components/service/fwu/agent/update_agent.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022, Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -15,6 +15,7 @@
 #include "fw_directory.h"
 #include "service/fwu/inspector/fw_inspector.h"
 #include "stream_manager.h"
+#include "components/service/fwu/common/update_agent_interface.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -26,39 +27,6 @@
 struct fw_store;
 
 /**
- * \brief Update process states
- *
- * The update_agent is responsible for ensuring that only a valid update flow
- * is followed by a client. To enforce the flow, public operations can only be
- * used in a valid state that reflects the FWU-A behavioral model.
- */
-enum fwu_state {
-	FWU_STATE_DEINITIALZED,
-	FWU_STATE_INITIALIZING,
-	FWU_STATE_REGULAR,
-	FWU_STATE_STAGING,
-	FWU_STATE_TRIAL_PENDING,
-	FWU_STATE_TRIAL
-};
-
-/**
- * \brief update_agent structure definition
- *
- * An update_agent instance is responsible for coordinating firmware updates applied
- * to a fw_store. An update_agent performs a security role by enforcing that a
- * valid flow is performed to update the fw store.
- */
-struct update_agent {
-	enum fwu_state state;
-	fw_inspector_inspect fw_inspect_method;
-	struct fw_store *fw_store;
-	struct fw_directory fw_directory;
-	struct stream_manager stream_manager;
-	uint8_t *image_dir_buf;
-	size_t image_dir_buf_size;
-};
-
-/**
  * \brief Initialise the update_agent
  *
  * \param[in]  update_agent    The subject update_agent
@@ -66,10 +34,11 @@
  * \param[in]  fw_inspect_method  fw_inspector inspect method
  * \param[in]  fw_store        The fw_store to manage
  *
- * \return Status (0 for success).  Uses fwu protocol status codes.
+ * \return Update agent instance or NULL on error
  */
-int update_agent_init(struct update_agent *update_agent, unsigned int boot_index,
-		      fw_inspector_inspect fw_inspect_method, struct fw_store *fw_store);
+struct update_agent *update_agent_init(unsigned int boot_index,
+				       fw_inspector_inspect fw_inspect_method,
+				       struct fw_store *fw_store);
 
 /**
  * \brief De-initialise the update_agent
@@ -78,109 +47,6 @@
  */
 void update_agent_deinit(struct update_agent *update_agent);
 
-/**
- * \brief Begin staging
- *
- * \param[in]  update_agent    The subject update_agent
- *
- * \return 0 on successfully transitioning to the STAGING state
- */
-int update_agent_begin_staging(struct update_agent *update_agent);
-
-/**
- * \brief End staging
- *
- * \param[in]  update_agent    The subject update_agent
- *
- * \return 0 on successfully transitioning to the TRIAL state
- */
-int update_agent_end_staging(struct update_agent *update_agent);
-
-/**
- * \brief Cancel staging
- *
- * \param[in]  update_agent    The subject update_agent
- *
- * \return 0 on successfully transitioning to the REGULAR state
- */
-int update_agent_cancel_staging(struct update_agent *update_agent);
-
-/**
- * \brief Accept an updated image
- *
- * \param[in]  update_agent    The subject update_agent
- * \param[in]  image_type_uuid Identifies the image to accept
- *
- * \return Status (0 on success)
- */
-int update_agent_accept(struct update_agent *update_agent,
-			const struct uuid_octets *image_type_uuid);
-
-/**
- * \brief Select previous version
- *
- *  Revert to a previous good version (if possible).
- *
- * \param[in]  update_agent    The subject update_agent
- *
- * \return Status (0 on success)
- */
-int update_agent_select_previous(struct update_agent *update_agent);
-
-/**
- * \brief Open a stream for accessing an fwu stream
- *
- * Used for reading or writing data for accessing images or other fwu
- * related objects.
- *
- * \param[in]  update_agent    The subject update_agent
- * \param[in]  uuid            Identifies the object to access
- * \param[out] handle          For subsequent read/write operations
- *
- * \return Status (0 on success)
- */
-int update_agent_open(struct update_agent *update_agent, const struct uuid_octets *uuid,
-		      uint32_t *handle);
-
-/**
- * \brief Close a stream and commit any writes to the stream
- *
- * \param[in]  update_agent    The subject update_agent
- * \param[in]  handle          The handle returned by open
- * \param[in]  accepted        Initial accepted state of an image
- *
- * \return Status (0 on success)
- */
-int update_agent_commit(struct update_agent *update_agent, uint32_t handle, bool accepted);
-
-/**
- * \brief Write to a previously opened stream
- *
- * \param[in]  update_agent    The subject update_agent
- * \param[in]  handle          The handle returned by open
- * \param[in]  data            Pointer to data
- * \param[in]  data_len        The data length
- *
- * \return Status (0 on success)
- */
-int update_agent_write_stream(struct update_agent *update_agent, uint32_t handle,
-			      const uint8_t *data, size_t data_len);
-
-/**
- * \brief Read from a previously opened stream
- *
- * \param[in]  update_agent    The subject update_agent
- * \param[in]  handle          The handle returned by open
- * \param[in]  buf             Pointer to buffer to copy to
- * \param[in]  buf_size        The size of the buffer
- * \param[out] read_len        The length of data read
- * \param[out] total_len       The total length of the object to read
- *
- * \return Status (0 on success)
- */
-int update_agent_read_stream(struct update_agent *update_agent, uint32_t handle, uint8_t *buf,
-			     size_t buf_size, size_t *read_len, size_t *total_len);
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/components/service/fwu/provider/fwu_provider.c b/components/service/fwu/provider/fwu_provider.c
index e94f653..33b744f 100644
--- a/components/service/fwu/provider/fwu_provider.c
+++ b/components/service/fwu/provider/fwu_provider.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2022-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -11,7 +11,7 @@
 #include "common/uuid/uuid.h"
 #include "protocols/rpc/common/packed-c/status.h"
 #include "protocols/service/fwu/packed-c/opcodes.h"
-#include "service/fwu/agent/update_agent.h"
+#include "service/fwu/common/update_agent_interface.h"
 #include "service/fwu/provider/serializer/fwu_provider_serializer.h"
 #include "fwu_uuid.h"
 
@@ -84,7 +84,7 @@
 {
 	struct fwu_provider *this_instance = (struct fwu_provider *)context;
 
-	req->service_status = update_agent_begin_staging(this_instance->update_agent);
+	req->service_status = update_agent_begin_staging(this_instance->update_agent, 0, 0, NULL);
 
 	return RPC_SUCCESS;
 }
@@ -121,7 +121,8 @@
 	if (rpc_status == RPC_SUCCESS) {
 		uint32_t handle = 0;
 		req->service_status =
-			update_agent_open(this_instance->update_agent, &image_type_uuid, &handle);
+			update_agent_open(this_instance->update_agent, &image_type_uuid, 0,
+					  &handle);
 
 		if (!req->service_status) {
 			struct rpc_buffer *resp_buf = &req->response;
@@ -202,12 +203,15 @@
 								&max_atomic_len);
 
 	if (rpc_status == RPC_SUCCESS) {
+		uint32_t progress = 0;
+		uint32_t total_work = 0;
+
 		req->service_status = update_agent_commit(this_instance->update_agent, handle,
-							  accepted);
+							  accepted, 0, &progress, &total_work);
 
 		if (!req->service_status) {
 			struct rpc_buffer *resp_buf = &req->response;
-			rpc_status = serializer->serialize_commit_resp(resp_buf, 0, 0);
+			rpc_status = serializer->serialize_commit_resp(resp_buf, progress, total_work);
 		}
 	}
 
@@ -226,8 +230,8 @@
 		rpc_status = serializer->deserialize_accept_req(req_buf, &image_type_uuid);
 
 	if (rpc_status == RPC_SUCCESS)
-		req->service_status = update_agent_accept(this_instance->update_agent,
-							  &image_type_uuid);
+		req->service_status = update_agent_accept_image(this_instance->update_agent,
+								&image_type_uuid);
 
 	return rpc_status;
 }
diff --git a/components/service/fwu/test/fwu_client/direct/direct_fwu_client.cpp b/components/service/fwu/test/fwu_client/direct/direct_fwu_client.cpp
index 6afd0f2..ecca254 100644
--- a/components/service/fwu/test/fwu_client/direct/direct_fwu_client.cpp
+++ b/components/service/fwu/test/fwu_client/direct/direct_fwu_client.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2022-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,9 +8,9 @@
 
 #include <cstring>
 
-#include "service/fwu/agent/update_agent.h"
+#include "service/fwu/common/update_agent_interface.h"
 
-direct_fwu_client::direct_fwu_client(struct update_agent *update_agent)
+direct_fwu_client::direct_fwu_client(struct update_agent **update_agent)
 	: fwu_client()
 	, m_update_agent(update_agent)
 	, m_read_buf()
@@ -27,48 +27,51 @@
 
 int direct_fwu_client::begin_staging(void)
 {
-	return update_agent_begin_staging(m_update_agent);
+	return update_agent_begin_staging(*m_update_agent, 0, 0, NULL);
 }
 
 int direct_fwu_client::end_staging(void)
 {
-	return update_agent_end_staging(m_update_agent);
+	return update_agent_end_staging(*m_update_agent);
 }
 
 int direct_fwu_client::cancel_staging(void)
 {
-	return update_agent_cancel_staging(m_update_agent);
+	return update_agent_cancel_staging(*m_update_agent);
 }
 
 int direct_fwu_client::accept(const struct uuid_octets *image_type_uuid)
 {
-	return update_agent_accept(m_update_agent, image_type_uuid);
+	return update_agent_accept_image(*m_update_agent, image_type_uuid);
 }
 
 int direct_fwu_client::select_previous(void)
 {
-	return update_agent_select_previous(m_update_agent);
+	return update_agent_select_previous(*m_update_agent);
 }
 
 int direct_fwu_client::open(const struct uuid_octets *uuid, uint32_t *handle)
 {
-	return update_agent_open(m_update_agent, uuid, handle);
+	return update_agent_open(*m_update_agent, uuid, 0, handle);
 }
 
 int direct_fwu_client::commit(uint32_t handle, bool accepted)
 {
-	return update_agent_commit(m_update_agent, handle, accepted);
+	uint32_t progress = 0;
+	uint32_t total_work = 0;
+
+	return update_agent_commit(*m_update_agent, handle, accepted, 0, &progress, &total_work);
 }
 
 int direct_fwu_client::write_stream(uint32_t handle, const uint8_t *data, size_t data_len)
 {
-	return update_agent_write_stream(m_update_agent, handle, data, data_len);
+	return update_agent_write_stream(*m_update_agent, handle, data, data_len);
 }
 
 int direct_fwu_client::read_stream(uint32_t handle, uint8_t *buf, size_t buf_size, size_t *read_len,
 				   size_t *total_len)
 {
-	int status = update_agent_read_stream(m_update_agent, handle, m_read_buf, READ_BUF_SIZE,
+	int status = update_agent_read_stream(*m_update_agent, handle, m_read_buf, READ_BUF_SIZE,
 					      read_len, total_len);
 
 	if (!status && buf && buf_size) {
diff --git a/components/service/fwu/test/fwu_client/direct/direct_fwu_client.h b/components/service/fwu/test/fwu_client/direct/direct_fwu_client.h
index bfa925b..3cd332d 100644
--- a/components/service/fwu/test/fwu_client/direct/direct_fwu_client.h
+++ b/components/service/fwu/test/fwu_client/direct/direct_fwu_client.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2022-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -19,7 +19,7 @@
  */
 class direct_fwu_client : public fwu_client {
 public:
-	explicit direct_fwu_client(struct update_agent *update_agent);
+	explicit direct_fwu_client(struct update_agent **update_agent);
 	~direct_fwu_client();
 
 	int begin_staging(void);
@@ -44,7 +44,7 @@
 private:
 	static const size_t READ_BUF_SIZE = 512;
 
-	struct update_agent *m_update_agent;
+	struct update_agent **m_update_agent;
 	uint8_t m_read_buf[READ_BUF_SIZE];
 };
 
diff --git a/components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.cpp b/components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.cpp
index 5415cc7..7718b63 100644
--- a/components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.cpp
+++ b/components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2022-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -14,6 +14,8 @@
 #include "common/endian/le.h"
 #include "media/disk/guid.h"
 #include "media/volume/index/volume_index.h"
+#include "service/fwu/agent/update_agent.h"
+#include "service/fwu/common/update_agent_interface.h"
 #include "service/fwu/fw_store/banked/metadata_serializer/v1/metadata_serializer_v1.h"
 #include "service/fwu/fw_store/banked/metadata_serializer/v2/metadata_serializer_v2.h"
 #include "service/fwu/fw_store/banked/volume_id.h"
@@ -54,16 +56,7 @@
 
 	install_factory_images(num_locations);
 
-	/* Initialise fwu service provider prior to boot to ensure that a
-	 * viable service interface exists to safely handle an incoming
-	 * request that occurs prior to the boot method being called.
-	 * Note that the update_agent is in the de-initialized state so
-	 * any operations will be denied.
-	 */
-	memset(&m_update_agent, 0, sizeof(m_update_agent));
-	m_update_agent.state = FWU_STATE_DEINITIALZED;
-
-	m_service_iface = fwu_provider_init(&m_fwu_provider, &m_update_agent);
+	m_service_iface = fwu_provider_init(&m_fwu_provider, NULL);
 
 	fwu_provider_register_serializer(&m_fwu_provider, TS_RPC_ENCODING_PACKED_C,
 					 packedc_fwu_provider_serializer_instance());
@@ -119,9 +112,11 @@
 	int status = banked_fw_store_init(&m_fw_store, select_metadata_serializer());
 	LONGS_EQUAL(0, status);
 
-	status = update_agent_init(&m_update_agent, m_boot_info.boot_index,
-				   direct_fw_inspector_inspect, &m_fw_store);
-	LONGS_EQUAL(0, status);
+	m_update_agent = update_agent_init(m_boot_info.boot_index, direct_fw_inspector_inspect,
+					   &m_fw_store);
+	CHECK(m_update_agent != NULL);
+
+	m_fwu_provider.update_agent = m_update_agent;
 
 	m_is_booted = true;
 }
@@ -132,9 +127,10 @@
 		return;
 
 	/* Ensure all install streams are closed */
-	update_agent_cancel_staging(&m_update_agent);
+	update_agent_cancel_staging(m_update_agent);
 
-	update_agent_deinit(&m_update_agent);
+	m_fwu_provider.update_agent = NULL;
+	update_agent_deinit(m_update_agent);
 	banked_fw_store_deinit(&m_fw_store);
 
 	m_is_booted = false;
diff --git a/components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.h b/components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.h
index f10d2c5..8a2bde3 100644
--- a/components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.h
+++ b/components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2022-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -15,13 +15,14 @@
 #include "service/block_storage/block_store/device/ram/ram_block_store.h"
 #include "service/block_storage/block_store/partitioned/partitioned_block_store.h"
 #include "service/fwu/agent/fw_directory.h"
-#include "service/fwu/agent/update_agent.h"
+#include "service/fwu/common/update_agent_interface.h"
 #include "service/fwu/fw_store/banked/bank_scheme.h"
 #include "service/fwu/fw_store/banked/banked_fw_store.h"
 #include "service/fwu/installer/copy/copy_installer.h"
 #include "service/fwu/installer/raw/raw_installer.h"
 #include "service/fwu/provider/fwu_provider.h"
 #include "service/fwu/test/fwu_client/fwu_client.h"
+#include "service/fwu/test/fwu_client/direct/direct_fwu_client.h"
 #include "service/fwu/test/fwu_dut/fwu_dut.h"
 #include "service/fwu/test/metadata_checker/metadata_checker.h"
 
@@ -119,7 +120,7 @@
 	struct copy_installer m_copy_installer_pool[MAX_LOCATIONS];
 
 	/* The core fwu service components */
-	struct update_agent m_update_agent;
+	struct update_agent *m_update_agent;
 	struct fw_store m_fw_store;
 	struct fwu_provider m_fwu_provider;
 };
diff --git a/deployments/component-test/component-test.cmake b/deployments/component-test/component-test.cmake
index b733d9c..f39473d 100644
--- a/deployments/component-test/component-test.cmake
+++ b/deployments/component-test/component-test.cmake
@@ -1,5 +1,5 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -106,6 +106,7 @@
 		"components/service/block_storage/factory/client"
 		"components/service/block_storage/factory/rpmb"
 		"components/service/fwu/agent"
+		"components/service/fwu/common"
 		"components/service/fwu/fw_store/banked"
 		"components/service/fwu/fw_store/banked/metadata_serializer/v1"
 		"components/service/fwu/fw_store/banked/metadata_serializer/v2"
diff --git a/deployments/fwu-tool/fwu.cmake b/deployments/fwu-tool/fwu.cmake
index d9cac39..fdaa550 100644
--- a/deployments/fwu-tool/fwu.cmake
+++ b/deployments/fwu-tool/fwu.cmake
@@ -1,5 +1,5 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2023-2024, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -24,6 +24,7 @@
 		"components/media/volume/index"
 		"components/service/common/include"
 		"components/service/fwu/agent"
+		"components/service/fwu/common"
 		"components/service/fwu/config"
 		"components/service/fwu/config/gpt"
 		"components/service/fwu/fw_store/banked"
diff --git a/deployments/fwu/env/commonsp/fwu_sp.c b/deployments/fwu/env/commonsp/fwu_sp.c
index c9bf4b1..21d78b7 100644
--- a/deployments/fwu/env/commonsp/fwu_sp.c
+++ b/deployments/fwu/env/commonsp/fwu_sp.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: BSD-3-Clause
 /*
- * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2023-2024, Arm Limited and Contributors. All rights reserved.
  */
 
 #include <stddef.h>
@@ -45,7 +45,7 @@
 	struct ts_rpc_endpoint_sp rpc_endpoint = { 0 };
 	struct fwu_provider service_provider = { 0 };
 	struct rpc_service_interface *service_iface = NULL;
-	struct update_agent update_agent = { 0 };
+	struct update_agent *update_agent = NULL;
 	struct fw_store fw_store = { 0 };
 	struct sp_msg req_msg = { 0 };
 	struct sp_msg resp_msg = { 0 };
@@ -89,14 +89,15 @@
 		goto fatal_error;
 	}
 
-	if (update_agent_init(&update_agent, HARD_CODED_BOOT_INDEX, direct_fw_inspector_inspect,
-			      &fw_store)) {
+	update_agent = update_agent_init(HARD_CODED_BOOT_INDEX, direct_fw_inspector_inspect,
+					 &fw_store);
+	if (!update_agent) {
 		EMSG("Failed to init update agent");
 		goto fatal_error;
 	}
 
 	/* Initialise the FWU service provider */
-	service_iface = fwu_provider_init(&service_provider, &update_agent);
+	service_iface = fwu_provider_init(&service_provider, update_agent);
 
 	if (!service_iface) {
 		EMSG("Failed to init service provider");
diff --git a/deployments/fwu/fwu.cmake b/deployments/fwu/fwu.cmake
index 7276360..2a7505e 100644
--- a/deployments/fwu/fwu.cmake
+++ b/deployments/fwu/fwu.cmake
@@ -1,5 +1,5 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2023-2024, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -19,6 +19,7 @@
 		"components/media/volume/index"
 		"components/service/common/include"
 		"components/service/fwu/agent"
+		"components/service/fwu/common"
 		"components/service/fwu/config"
 		"components/service/fwu/config/gpt"
 		"components/service/fwu/fw_store/banked"
diff --git a/deployments/ts-service-test/linux-pc/CMakeLists.txt b/deployments/ts-service-test/linux-pc/CMakeLists.txt
index b0cd912..4ce36e2 100644
--- a/deployments/ts-service-test/linux-pc/CMakeLists.txt
+++ b/deployments/ts-service-test/linux-pc/CMakeLists.txt
@@ -1,5 +1,5 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -97,6 +97,7 @@
 		"components/service/block_storage/test/service"
 		"components/service/common/provider"
 		"components/service/fwu/agent"
+		"components/service/fwu/common"
 		"components/service/fwu/fw_store/banked"
 		"components/service/fwu/fw_store/banked/metadata_serializer/v1"
 		"components/service/fwu/fw_store/banked/metadata_serializer/v2"