PFW: Manage subsystem plugin dependency

BZ: 15204

As subsystem plugins might depend on one another, they can't always be all
loaded at once. Because a certain order must sometimes be respected, the
loading process has now become iterative, not merely failing upon the first
loading failure.

- Fixed a missing carriage return in the configurable domains listing
functionallity

Change-Id: I7e0d6ecbb258fcb1acaad78359e65f0e132d09ab
Signed-off-by: Patrick Benavoli <patrickx.benavoli@intel.com>
Reviewed-on: http://android.intel.com:8080/25408
Reviewed-by: Barthes, FabienX <fabienx.barthes@intel.com>
Tested-by: Barthes, FabienX <fabienx.barthes@intel.com>
Reviewed-by: buildbot <buildbot@intel.com>
Tested-by: buildbot <buildbot@intel.com>
diff --git a/parameter/ConfigurableDomains.cpp b/parameter/ConfigurableDomains.cpp
index 597d453..d021d8c 100644
--- a/parameter/ConfigurableDomains.cpp
+++ b/parameter/ConfigurableDomains.cpp
@@ -381,8 +381,9 @@
         // Sequence awareness
         if (pChildConfigurableDomain->getSequenceAwareness()) {
 
-            strResult += " [sequence aware]\n";
+            strResult += " [sequence aware]";
         }
+        strResult += "\n";
     }
 }
 
diff --git a/parameter/SystemClass.cpp b/parameter/SystemClass.cpp
index 97fc89f..532473a 100644
--- a/parameter/SystemClass.cpp
+++ b/parameter/SystemClass.cpp
@@ -37,6 +37,7 @@
 #include "AutoLog.h"
 #include "VirtualSubsystem.h"
 #include "NamedElementBuilderTemplate.h"
+#include <assert.h>
 
 #define base CConfigurableElement
 
@@ -80,7 +81,7 @@
     CAutoLog autoLlog(this, "Loading subsystem plugins");
 
     // Plugin list
-    vector<string> astrPluginFiles;
+    list<string> lstrPluginFiles;
 
     uint32_t uiFolderLocation;
 
@@ -90,77 +91,40 @@
         string strPluginPath = astrPluginFolderPaths[uiFolderLocation] + "/";
 
         // Get plugin list
-        getPluginFiles(strPluginPath, astrPluginFiles);
+        getPluginFiles(strPluginPath, lstrPluginFiles);
     }
     // Check at least one subsystem plugin available
-    if (!astrPluginFiles.size()) {
+    if (!lstrPluginFiles.size()) {
 
         // No plugin found?
-        strError = "No subsystem plugin found";
+        log("No subsystem plugin found");
 
-        return false;
+        // Don't bail out now that we have virtual subsystems
     }
 
-    // Actually load plugins
-    uint32_t uiPlugin;
     // Start clean
     _pSubsystemLibrary->clean();
 
-    for (uiPlugin = 0; uiPlugin < astrPluginFiles.size(); uiPlugin++) {
+    // Actually load plugins
+    while (lstrPluginFiles.size()) {
 
-        string strPluginFileName = astrPluginFiles[uiPlugin];
+        // Because plugins might depend on one another, loading will be done
+        // as an iteration process that finishes successfully when the remaining
+        // list of plugins to load gets empty or unsuccessfully if the loading
+        // process failed to load at least one of them
 
-        log("Loading subsystem plugin path \"%s\"", strPluginFileName.c_str());
+        // Attempt to load the complete list
+        if (!loadPlugins(lstrPluginFiles, strError)) {
 
-        void* lib_handle = dlopen(strPluginFileName.c_str(), RTLD_LAZY);
+            // Display the list of plugins we were unable to load
 
-        if (!lib_handle) {
-
-            // Return error
-            const char* pcError = dlerror();
-
-            if (pcError) {
-
-                strError = pcError;
-            } else {
-
-                strError = "Unable to load subsystem plugin " + strPluginFileName;
-            }
-
+            // Leave clean
             _pSubsystemLibrary->clean();
 
             return false;
         }
-
-        // Extract plugin type out of file name
-        string strPluginPattern = gpcPluginPattern;
-        string strLibraryPrefix = gpcLibraryPrefix;
-        // Remove folder
-        int32_t iSlashPos = strPluginFileName.rfind('/') + 1 + strLibraryPrefix.length();
-        // Get type
-        string strPluginType = strPluginFileName.substr(iSlashPos, strPluginFileName.length() - iSlashPos - strPluginPattern.length());
-
-        // Make it upper case
-        std::transform(strPluginType.begin(), strPluginType.end(), strPluginType.begin(), ::toupper);
-
-        // Get plugin symbol
-        string strPluginSymbol = gpcPluginSymbolPrefix + strPluginType + gpcPluginSymbolSuffix;
-
-        // Load symbol from library
-        GetSusbystemBuilder pfnGetSusbystemBuilder = (GetSusbystemBuilder)dlsym(lib_handle, strPluginSymbol.c_str());
-
-        if (!pfnGetSusbystemBuilder) {
-
-            strError = "Subsystem plugin " + strPluginFileName + " does not contain " + strPluginSymbol + " symbol.";
-
-            _pSubsystemLibrary->clean();
-
-            return false;
-        }
-
-        // Fill library
-        pfnGetSusbystemBuilder(_pSubsystemLibrary);
     }
+    log("All subsystem plugins successfully loaded");
 
     // Add virtual subsystem builder
     _pSubsystemLibrary->addElementBuilder(new TNamedElementBuilderTemplate<CVirtualSubsystem>("Virtual"));
@@ -168,7 +132,8 @@
     return true;
 }
 
-bool CSystemClass::getPluginFiles(const string& strPluginPath, vector<string>& astrPluginFiles) const
+// Subsystem plugins
+bool CSystemClass::getPluginFiles(const string& strPluginPath, list<string>& lstrPluginFiles) const
 {
     log("Seeking subsystem plugins from folder \"%s\"", strPluginPath.c_str());
 
@@ -192,7 +157,7 @@
 
         if (uiPatternPos != (size_t)-1 && uiPatternPos == strFileName.size() - strPluginPattern.size()) {
             // Found plugin
-            astrPluginFiles.push_back(strPluginPath + strFileName);
+            lstrPluginFiles.push_back(strPluginPath + strFileName);
         }
     }
 
@@ -202,6 +167,95 @@
     return true;
 }
 
+// Plugin symbol computation
+string CSystemClass::getPluginSymbol(const string& strPluginPath)
+{
+    // Extract plugin type out of file name
+    string strPluginPattern = gpcPluginPattern;
+    string strLibraryPrefix = gpcLibraryPrefix;
+
+    // Remove folder
+    int32_t iSlashPos = strPluginPath.rfind('/') + 1 + strLibraryPrefix.length();
+
+    // Get type
+    string strPluginType = strPluginPath.substr(iSlashPos, strPluginPath.length() - iSlashPos - strPluginPattern.length());
+
+    // Make it upper case
+    std::transform(strPluginType.begin(), strPluginType.end(), strPluginType.begin(), ::toupper);
+
+    // Get plugin symbol
+    return gpcPluginSymbolPrefix + strPluginType + gpcPluginSymbolSuffix;
+}
+
+// Plugin loading
+bool CSystemClass::loadPlugins(list<string>& lstrPluginFiles, string& strError)
+{
+    assert(lstrPluginFiles.size());
+
+    bool bAtLeastOneSybsystemPluginSuccessfullyLoaded = false;
+
+    list<string>::iterator it = lstrPluginFiles.begin();
+
+    while (it != lstrPluginFiles.end()) {
+
+        string strPluginFileName = *it;
+
+        log("Attempting to load subsystem plugin path \"%s\"", strPluginFileName.c_str());
+
+        // Load attempt
+        void* lib_handle = dlopen(strPluginFileName.c_str(), RTLD_LAZY);
+
+        if (!lib_handle) {
+
+            // Failed
+            log("Plugin load failed, proceeding on with remaining ones");
+
+            // Next plugin
+            ++it;
+
+            continue;
+        }
+
+        // Get plugin symbol
+        string strPluginSymbol = getPluginSymbol(strPluginFileName);
+
+        // Load symbol from library
+        GetSusbystemBuilder pfnGetSusbystemBuilder = (GetSusbystemBuilder)dlsym(lib_handle, strPluginSymbol.c_str());
+
+        if (!pfnGetSusbystemBuilder) {
+
+            strError = "Subsystem plugin " + strPluginFileName + " does not contain " + strPluginSymbol + " symbol.";
+
+            return false;
+        }
+
+        // Fill library
+        pfnGetSusbystemBuilder(_pSubsystemLibrary);
+
+        // Account for this success
+        bAtLeastOneSybsystemPluginSuccessfullyLoaded = true;
+
+        // Remove successfully loaded plugin from list and select next
+        lstrPluginFiles.erase(it++);
+    }
+
+    // Check for success
+    if (!bAtLeastOneSybsystemPluginSuccessfullyLoaded) {
+
+        // Return list of plugins we were unable to load
+        strError = "Unable to load the following plugins:\n";
+
+        for (it = lstrPluginFiles.begin(); it != lstrPluginFiles.end(); ++it) {
+
+            strError += *it + "\n";
+        }
+
+        return false;
+    }
+
+    return true;
+}
+
 const CSubsystemLibrary* CSystemClass::getSubsystemLibrary() const
 {
     return _pSubsystemLibrary;
diff --git a/parameter/SystemClass.h b/parameter/SystemClass.h
index d80ab52..512c5ec 100644
--- a/parameter/SystemClass.h
+++ b/parameter/SystemClass.h
@@ -31,7 +31,7 @@
 #pragma once
 
 #include "ConfigurableElement.h"
-#include <vector>
+#include <list>
 
 class CSubsystemLibrary;
 
@@ -54,7 +54,13 @@
     virtual bool childrenAreDynamic() const;
 
     // Subsystem plugins
-    bool getPluginFiles(const string& strPluginPath, vector<string>& astrPluginFiles) const;
+    bool getPluginFiles(const string& strPluginPath, list<string>& lstrPluginFiles) const;
+
+    // Plugin symbol computation
+    static string getPluginSymbol(const string& strPluginPath);
+
+    // Plugin loading
+    bool loadPlugins(list<string>& lstrPluginFiles, string& strError);
 
     // ref only
     CSubsystemLibrary* _pSubsystemLibrary;