Github #273 Handle failure to initialise BackendContext in Runtime

Define CreateBackendContext to throw BackendUnavailableException
if necessary runtime components are missing.

Handle this in the constructor of Runtime by not adding those
backends to the internal DeviceSpec owned by the Runtime.

Signed-off-by: Matthew Bentham <Matthew.Bentham@arm.com>
Change-Id: Iadffb5240e32e1f105683c4d361276b92d1e720c
diff --git a/src/armnn/DeviceSpec.hpp b/src/armnn/DeviceSpec.hpp
index 703a4b1..a1457cf 100644
--- a/src/armnn/DeviceSpec.hpp
+++ b/src/armnn/DeviceSpec.hpp
@@ -14,6 +14,9 @@
 class DeviceSpec : public IDeviceSpec
 {
 public:
+    DeviceSpec()
+    {}
+
     DeviceSpec(const BackendIdSet& supportedBackends)
         : m_SupportedBackends{supportedBackends} {}
 
@@ -48,7 +51,6 @@
     }
 
 private:
-    DeviceSpec() = delete;
     BackendIdSet m_SupportedBackends;
     BackendIdSet m_DynamicBackends;
 };
diff --git a/src/armnn/Runtime.cpp b/src/armnn/Runtime.cpp
index 2d7269a..47c998a 100644
--- a/src/armnn/Runtime.cpp
+++ b/src/armnn/Runtime.cpp
@@ -153,7 +153,6 @@
 
 Runtime::Runtime(const CreationOptions& options)
     : m_NetworkIdCounter(0)
-    , m_DeviceSpec{BackendRegistryInstance().GetBackendIds()}
 {
     ARMNN_LOG(info) << "ArmNN v" << ARMNN_VERSION << "\n";
 
@@ -164,12 +163,11 @@
     // goes through the backend registry
     LoadDynamicBackends(options.m_DynamicBackendsPath);
 
+    BackendIdSet supportedBackends;
     for (const auto& id : BackendRegistryInstance().GetBackendIds())
     {
         // Store backend contexts for the supported ones
-        const BackendIdSet& supportedBackends = m_DeviceSpec.GetSupportedBackends();
-        if (supportedBackends.find(id) != supportedBackends.end())
-        {
+        try {
             auto factoryFun = BackendRegistryInstance().GetFactory(id);
             auto backend = factoryFun();
             BOOST_ASSERT(backend.get() != nullptr);
@@ -182,8 +180,15 @@
             {
                 m_BackendContexts.emplace(std::make_pair(id, std::move(context)));
             }
+            supportedBackends.emplace(id);
         }
+        catch (const BackendUnavailableException&)
+        {
+            // Ignore backends which are unavailable
+        }
+
     }
+    m_DeviceSpec.AddSupportedBackends(supportedBackends);
 }
 
 Runtime::~Runtime()
diff --git a/src/armnn/Runtime.hpp b/src/armnn/Runtime.hpp
index e5debbf..2ad3c96 100644
--- a/src/armnn/Runtime.hpp
+++ b/src/armnn/Runtime.hpp
@@ -73,8 +73,6 @@
     virtual void RegisterDebugCallback(NetworkId networkId, const DebugCallbackFunction& func) override;
 
     /// Creates a runtime for workload execution.
-    /// May throw a ClRuntimeUnavailableException if @a defaultComputeDevice requires a CL runtime but
-    /// it cannot be setup for some reason.
     Runtime(const CreationOptions& options);
 
     ~Runtime();