Support modular extension of service provider capabilities
To allow a service provider to be scalable in a modular way, the
existing chain-of-resopnsibility facilty provided by the base
service_provider is exploited to allow a set of sub providers
to extend the capabilities of the base provider. The first
use of this will be to support modular extension of the crypto
service provider.
Signed-off-by: Julian Hall <julian.hall@arm.com>
Change-Id: I4369d7a9cb99e54403768a9e3459b0ba1ac8f812
diff --git a/components/service/common/provider/service_provider.c b/components/service/common/provider/service_provider.c
index f11c303..19bd088 100644
--- a/components/service/common/provider/service_provider.c
+++ b/components/service/common/provider/service_provider.c
@@ -64,3 +64,10 @@
sp->successor = NULL;
}
+
+void service_provider_extend(struct service_provider *context,
+ struct service_provider *sub_provider)
+{
+ sub_provider->successor = context->successor;
+ context->successor = &sub_provider->iface;
+}
diff --git a/components/service/common/provider/service_provider.h b/components/service/common/provider/service_provider.h
index 508a93f..a4f15e4 100644
--- a/components/service/common/provider/service_provider.h
+++ b/components/service/common/provider/service_provider.h
@@ -59,6 +59,21 @@
const struct service_handler *handlers,
size_t num_handlers);
+/*
+ * Extend the core set of operations provided by a service provider by
+ * adding a sub provider that will add a capability. This facility
+ * allows a deployment to customize the set of operations
+ * supported to meet requirements by only extending the core service
+ * provider if needed.
+ */
+void service_provider_extend(struct service_provider *context,
+ struct service_provider *sub_provider);
+
+/*
+ * Link a successor to this service provider to extend the chain of responsibility
+ * to allow call handling to be delegated to different components. Used to support
+ * modular configuration of service capabilities.
+ */
static inline void service_provider_link_successor(struct service_provider *sp,
struct rpc_interface *successor)
{
diff --git a/components/service/common/provider/test/service_framework_tests.cpp b/components/service/common/provider/test/service_framework_tests.cpp
index 6483c4b..49ec163 100644
--- a/components/service/common/provider/test/service_framework_tests.cpp
+++ b/components/service/common/provider/test/service_framework_tests.cpp
@@ -78,14 +78,14 @@
int opstatus;
handle = rpc_caller_begin(caller, &req_buf, req_len);
- CHECK(handle);
+ CHECK_TRUE(handle);
rpc_status_t rpc_status = rpc_caller_invoke(caller, handle, SOME_ARBITRARY_OPCODE,
&opstatus, &resp_buf, &resp_len);
rpc_caller_end(caller, handle);
- CHECK_EQUAL(TS_RPC_ERROR_INVALID_OPCODE, rpc_status);
+ LONGS_EQUAL(TS_RPC_ERROR_INVALID_OPCODE, rpc_status);
}
TEST(ServiceFrameworkTests, serviceWithOps)
@@ -114,7 +114,7 @@
/* Expect this call transaction to succeed */
handle = rpc_caller_begin(caller, &req_buf, req_len);
- CHECK(handle);
+ CHECK_TRUE(handle);
rpc_status = rpc_caller_invoke(caller, handle, SOME_ARBITRARY_OPCODE,
&opstatus, &resp_buf, &resp_len);
@@ -123,13 +123,13 @@
rpc_caller_end(caller, handle);
- CHECK_EQUAL(TS_RPC_CALL_ACCEPTED, rpc_status);
- CHECK_EQUAL(SERVICE_SPECIFIC_SUCCESS_CODE, opstatus);
- CHECK(respString == "Yay!");
+ LONGS_EQUAL(TS_RPC_CALL_ACCEPTED, rpc_status);
+ LONGS_EQUAL(SERVICE_SPECIFIC_SUCCESS_CODE, opstatus);
+ STRCMP_EQUAL("Yay!", respString.c_str());
/* Expect this call transaction to fail */
handle = rpc_caller_begin(caller, &req_buf, req_len);
- CHECK(handle);
+ CHECK_TRUE(handle);
rpc_status = rpc_caller_invoke(caller, handle, ANOTHER_ARBITRARY_OPCODE,
&opstatus, &resp_buf, &resp_len);
@@ -138,18 +138,116 @@
rpc_caller_end(caller, handle);
- CHECK_EQUAL(TS_RPC_CALL_ACCEPTED, rpc_status);
- CHECK_EQUAL(SERVICE_SPECIFIC_ERROR_CODE, opstatus);
- CHECK(respString == "Ehh!");
+ LONGS_EQUAL(TS_RPC_CALL_ACCEPTED, rpc_status);
+ LONGS_EQUAL(SERVICE_SPECIFIC_ERROR_CODE, opstatus);
+ STRCMP_EQUAL("Ehh!", respString.c_str());
/* Try an unsupported opcode */
handle = rpc_caller_begin(caller, &req_buf, req_len);
- CHECK(handle);
+ CHECK_TRUE(handle);
rpc_status = rpc_caller_invoke(caller, handle, YET_ANOTHER_ARBITRARY_OPCODE,
&opstatus, &resp_buf, &resp_len);
rpc_caller_end(caller, handle);
- CHECK_EQUAL(TS_RPC_ERROR_INVALID_OPCODE, rpc_status);
+ LONGS_EQUAL(TS_RPC_ERROR_INVALID_OPCODE, rpc_status);
+}
+
+TEST(ServiceFrameworkTests, serviceProviderChain)
+{
+ /* Construct the base service provider */
+ struct service_handler base_handlers[0];
+ base_handlers[0].opcode = 100;
+ base_handlers[0].invoke = handlerThatSucceeds;
+
+ struct service_provider base_provider;
+ service_provider_init(&base_provider, &base_provider, base_handlers, 1);
+
+ /* Construct a sub provider and extend the base */
+ struct service_handler sub0_handlers[0];
+ sub0_handlers[0].opcode = 200;
+ sub0_handlers[0].invoke = handlerThatSucceeds;
+
+ struct service_provider sub0_provider;
+ service_provider_init(&sub0_provider, &sub0_provider, sub0_handlers, 1);
+ service_provider_extend(&base_provider, &sub0_provider);
+
+ /* Construct another sub provider and extend the base */
+ struct service_handler sub1_handlers[0];
+ sub1_handlers[0].opcode = 300;
+ sub1_handlers[0].invoke = handlerThatSucceeds;
+
+ struct service_provider sub1_provider;
+ service_provider_init(&sub1_provider, &sub1_provider, sub1_handlers, 1);
+ service_provider_extend(&base_provider, &sub1_provider);
+
+
+ struct rpc_caller *caller = direct_caller_init_default(&m_direct_caller,
+ service_provider_get_rpc_interface(&base_provider));
+
+ rpc_call_handle handle;
+ rpc_status_t rpc_status;
+ uint8_t *req_buf;
+ uint8_t *resp_buf;
+ size_t req_len = 100;
+ size_t resp_len;
+ int opstatus;
+ std::string respString;
+
+ /* Expect calls that will be handled by all three chained service providers to succeed */
+ handle = rpc_caller_begin(caller, &req_buf, req_len);
+ CHECK_TRUE(handle);
+
+ rpc_status = rpc_caller_invoke(caller, handle, 100,
+ &opstatus, &resp_buf, &resp_len);
+
+ respString = std::string((const char*)resp_buf, resp_len);
+
+ rpc_caller_end(caller, handle);
+
+ LONGS_EQUAL(TS_RPC_CALL_ACCEPTED, rpc_status);
+ LONGS_EQUAL(SERVICE_SPECIFIC_SUCCESS_CODE, opstatus);
+ STRCMP_EQUAL("Yay!", respString.c_str());
+
+ /* This one should beb handled by sub0 */
+ handle = rpc_caller_begin(caller, &req_buf, req_len);
+ CHECK_TRUE(handle);
+
+ rpc_status = rpc_caller_invoke(caller, handle, 200,
+ &opstatus, &resp_buf, &resp_len);
+
+ respString = std::string((const char*)resp_buf, resp_len);
+
+ rpc_caller_end(caller, handle);
+
+ LONGS_EQUAL(TS_RPC_CALL_ACCEPTED, rpc_status);
+ LONGS_EQUAL(SERVICE_SPECIFIC_SUCCESS_CODE, opstatus);
+ STRCMP_EQUAL("Yay!", respString.c_str());
+
+ /* This one should beb handled by sub1 */
+ handle = rpc_caller_begin(caller, &req_buf, req_len);
+ CHECK_TRUE(handle);
+
+ rpc_status = rpc_caller_invoke(caller, handle, 300,
+ &opstatus, &resp_buf, &resp_len);
+
+ respString = std::string((const char*)resp_buf, resp_len);
+
+ rpc_caller_end(caller, handle);
+
+ LONGS_EQUAL(TS_RPC_CALL_ACCEPTED, rpc_status);
+ LONGS_EQUAL(SERVICE_SPECIFIC_SUCCESS_CODE, opstatus);
+ STRCMP_EQUAL("Yay!", respString.c_str());
+
+ /* Try an unsupported opcode */
+ handle = rpc_caller_begin(caller, &req_buf, req_len);
+ CHECK_TRUE(handle);
+
+ rpc_status = rpc_caller_invoke(caller, handle, 400,
+ &opstatus, &resp_buf, &resp_len);
+
+ rpc_caller_end(caller, handle);
+
+ LONGS_EQUAL(TS_RPC_ERROR_INVALID_OPCODE, rpc_status);
}
diff --git a/components/service/crypto/provider/crypto_provider.c b/components/service/crypto/provider/crypto_provider.c
index c3d55b5..6777fd2 100644
--- a/components/service/crypto/provider/crypto_provider.c
+++ b/components/service/crypto/provider/crypto_provider.c
@@ -75,6 +75,12 @@
context->serializers[encoding] = serializer;
}
+void crypto_provider_extend(struct crypto_provider *context,
+ struct service_provider *sub_provider)
+{
+ service_provider_extend(&context->base_provider, sub_provider);
+}
+
static const struct crypto_provider_serializer* get_crypto_serializer(void *context,
const struct call_req *req)
{
diff --git a/components/service/crypto/provider/crypto_provider.h b/components/service/crypto/provider/crypto_provider.h
index a45b14c..7cd91a9 100644
--- a/components/service/crypto/provider/crypto_provider.h
+++ b/components/service/crypto/provider/crypto_provider.h
@@ -46,6 +46,12 @@
void crypto_provider_register_serializer(struct crypto_provider *context,
unsigned int encoding, const struct crypto_provider_serializer *serializer);
+/*
+ * Extend the core set of operations provided by the crypto provider.
+ */
+void crypto_provider_extend(struct crypto_provider *context,
+ struct service_provider *sub_provider);
+
#ifdef __cplusplus
} /* extern "C" */
#endif