HalGroup is the base class for HalManifest and CompatibilityMatrix.

Move common functions to HalGroup.h

Test: libvintf_test
Test: vintf_object_test
Bug: 38217107
Change-Id: I8acac6f4fcf79e2c9c3ec9df475f341c772aa983
diff --git a/CompatibilityMatrix.cpp b/CompatibilityMatrix.cpp
index 379fd78..627c238 100644
--- a/CompatibilityMatrix.cpp
+++ b/CompatibilityMatrix.cpp
@@ -24,8 +24,7 @@
 constexpr Version CompatibilityMatrix::kVersion;
 
 bool CompatibilityMatrix::add(MatrixHal &&hal) {
-    mHals.emplace(hal.name, std::move(hal));
-    return true;
+    return HalGroup<MatrixHal>::add(std::move(hal));
 }
 
 bool CompatibilityMatrix::add(MatrixKernel &&kernel) {
@@ -36,18 +35,6 @@
     return true;
 }
 
-ConstMultiMapValueIterable<std::string, MatrixHal> CompatibilityMatrix::getHals() const {
-    return ConstMultiMapValueIterable<std::string, MatrixHal>(mHals);
-}
-
-MatrixHal *CompatibilityMatrix::getAnyHal(const std::string &name) {
-    auto it = mHals.find(name);
-    if (it == mHals.end()) {
-        return nullptr;
-    }
-    return &(it->second);
-}
-
 const MatrixKernel *CompatibilityMatrix::findKernel(const KernelVersion &v) const {
     if (mType != SchemaType::FRAMEWORK) {
         return nullptr;
diff --git a/HalManifest.cpp b/HalManifest.cpp
index fbbfa2e..efa543e 100644
--- a/HalManifest.cpp
+++ b/HalManifest.cpp
@@ -55,14 +55,6 @@
     return true;
 }
 
-bool HalManifest::add(ManifestHal&& hal) {
-    if (!shouldAdd(hal)) {
-        return false;
-    }
-    mHals.emplace(hal.name, std::move(hal));  // always succeed
-    return true;
-}
-
 std::set<std::string> HalManifest::getHalNames() const {
     std::set<std::string> names{};
     for (const auto &hal : mHals) {
@@ -91,14 +83,6 @@
     return interfaceNames;
 }
 
-ManifestHal *HalManifest::getAnyHal(const std::string &name) {
-    auto it = mHals.find(name);
-    if (it == mHals.end()) {
-        return nullptr;
-    }
-    return &(it->second);
-}
-
 std::vector<const ManifestHal *> HalManifest::getHals(const std::string &name) const {
     std::vector<const ManifestHal *> ret;
     auto range = mHals.equal_range(name);
@@ -154,7 +138,7 @@
 }
 
 ConstMultiMapValueIterable<std::string, ManifestHal> HalManifest::getHals() const {
-    return ConstMultiMapValueIterable<std::string, ManifestHal>(mHals);
+    return HalGroup<ManifestHal>::getHals();
 }
 
 std::set<Version> HalManifest::getSupportedVersions(const std::string &name) const {
diff --git a/include/vintf/CompatibilityMatrix.h b/include/vintf/CompatibilityMatrix.h
index 30344dd..228fe5e 100644
--- a/include/vintf/CompatibilityMatrix.h
+++ b/include/vintf/CompatibilityMatrix.h
@@ -22,19 +22,19 @@
 
 #include <utils/Errors.h>
 
+#include "HalGroup.h"
+#include "MapValueIterator.h"
 #include "MatrixHal.h"
 #include "MatrixKernel.h"
-#include "MapValueIterator.h"
-#include "Sepolicy.h"
 #include "SchemaType.h"
+#include "Sepolicy.h"
 #include "Vndk.h"
 
 namespace android {
 namespace vintf {
 
 // Compatibility matrix defines what hardware does the framework requires.
-struct CompatibilityMatrix {
-
+struct CompatibilityMatrix : public HalGroup<MatrixHal> {
     // Create a framework compatibility matrix.
     CompatibilityMatrix() : mType(SchemaType::FRAMEWORK) {};
 
@@ -49,13 +49,6 @@
     // Find a MatrixKernel entry that has version v. nullptr if not found.
     const MatrixKernel *findKernel(const KernelVersion &v) const;
 
-    // Return an iterable to all MatrixHal objects. Call it as follows:
-    // for (const MatrixHal &e : cm.getHals()) { }
-    ConstMultiMapValueIterable<std::string, MatrixHal> getHals() const;
-
-    // for constructing matrix programitically only.
-    MatrixHal *getAnyHal(const std::string &name);
-
     status_t fetchAllInformation(const std::string &path);
 
     friend struct HalManifest;
@@ -68,9 +61,6 @@
 
     SchemaType mType;
 
-    // sorted map from component name to the entry.
-    std::multimap<std::string, MatrixHal> mHals;
-
     // entries only for framework compatibility matrix.
     struct {
         std::vector<MatrixKernel> mKernels;
diff --git a/include/vintf/HalGroup.h b/include/vintf/HalGroup.h
new file mode 100644
index 0000000..52bac11
--- /dev/null
+++ b/include/vintf/HalGroup.h
@@ -0,0 +1,59 @@
+
+#ifndef ANDROID_VINTF_HAL_GROUP_H
+#define ANDROID_VINTF_HAL_GROUP_H
+
+#include <map>
+
+#include "MapValueIterator.h"
+
+namespace android {
+namespace vintf {
+
+// A HalGroup is a wrapped multimap from name to Hal.
+// Hal.getName() must return a string indicating the name.
+template <typename Hal>
+struct HalGroup {
+   public:
+    virtual ~HalGroup() {}
+
+    // Add an hal to this HalGroup so that it can be constructed programatically.
+    bool add(Hal&& hal) {
+        if (!shouldAdd(hal)) {
+            return false;
+        }
+        mHals.emplace(hal.getName(), std::move(hal));  // always succeed
+        return true;
+    }
+
+   protected:
+    // sorted map from component name to the component.
+    // The component name looks like: android.hardware.foo
+    std::multimap<std::string, Hal> mHals;
+
+    // override this to filter for add.
+    virtual bool shouldAdd(const Hal&) const { return true; }
+
+    // Return an iterable to all ManifestHal objects. Call it as follows:
+    // for (const auto& e : vm.getHals()) { }
+    ConstMultiMapValueIterable<std::string, Hal> getHals() const {
+        return ConstMultiMapValueIterable<std::string, Hal>(mHals);
+    }
+
+    // Get any HAL component based on the component name. Return any one
+    // if multiple. Return nullptr if the component does not exist. This is only
+    // for creating objects programatically.
+    // The component name looks like:
+    // android.hardware.foo
+    Hal* getAnyHal(const std::string& name) {
+        auto it = mHals.find(name);
+        if (it == mHals.end()) {
+            return nullptr;
+        }
+        return &(it->second);
+    }
+};
+
+}  // namespace vintf
+}  // namespace android
+
+#endif  // ANDROID_VINTF_HAL_GROUP_H
diff --git a/include/vintf/HalManifest.h b/include/vintf/HalManifest.h
index 4a983d1..9e01330 100644
--- a/include/vintf/HalManifest.h
+++ b/include/vintf/HalManifest.h
@@ -23,6 +23,7 @@
 #include <utils/Errors.h>
 #include <vector>
 
+#include "HalGroup.h"
 #include "ManifestHal.h"
 #include "MapValueIterator.h"
 #include "SchemaType.h"
@@ -37,9 +38,8 @@
 
 // A HalManifest is reported by the hardware and query-able from
 // framework code. This is the API for the framework.
-struct HalManifest {
-public:
-
+struct HalManifest : public HalGroup<ManifestHal> {
+   public:
     // manifest.version
     constexpr static Version kVersion{1, 0};
 
@@ -92,9 +92,6 @@
     // Generate a compatibility matrix such that checkCompatibility will return true.
     CompatibilityMatrix generateCompatibleMatrix() const;
 
-    // Add an hal to this manifest so that a HalManifest can be constructed programatically.
-    bool add(ManifestHal &&hal);
-
     // Returns all component names.
     std::set<std::string> getHalNames() const;
 
@@ -123,7 +120,11 @@
     // Abort if type != framework.
     const std::vector<Vndk> &vndks() const;
 
-private:
+   protected:
+    // Check before add()
+    bool shouldAdd(const ManifestHal& toAdd) const override;
+
+   private:
     friend struct HalManifestConverter;
     friend class VintfObject;
     friend class AssembleVintf;
@@ -131,20 +132,10 @@
     friend std::string dump(const HalManifest &vm);
     friend bool operator==(const HalManifest &lft, const HalManifest &rgt);
 
-    // Check before add()
-    bool shouldAdd(const ManifestHal& toAdd) const;
-
     // Return an iterable to all ManifestHal objects. Call it as follows:
     // for (const ManifestHal &e : vm.getHals()) { }
     ConstMultiMapValueIterable<std::string, ManifestHal> getHals() const;
 
-    // Get any HAL component based on the component name. Return any one
-    // if multiple. Return nullptr if the component does not exist. This is only
-    // for creating HalManifest objects programatically.
-    // The component name looks like:
-    // android.hardware.foo
-    ManifestHal *getAnyHal(const std::string &name);
-
     status_t fetchAllInformation(const std::string &path);
 
     // Check if all instances in matrixHal is supported in this manifest.
@@ -152,10 +143,6 @@
 
     SchemaType mType;
 
-    // sorted map from component name to the component.
-    // The component name looks like: android.hardware.foo
-    std::multimap<std::string, ManifestHal> mHals;
-
     // entries for device hal manifest only
     struct {
         Version mSepolicyVersion;
diff --git a/include/vintf/ManifestHal.h b/include/vintf/ManifestHal.h
index 15d2300..cd862ff 100644
--- a/include/vintf/ManifestHal.h
+++ b/include/vintf/ManifestHal.h
@@ -48,7 +48,9 @@
         return transportArch.transport;
     }
 
-private:
+    inline const std::string& getName() const { return name; }
+
+   private:
     friend struct LibVintfTest;
     friend struct ManifestHalConverter;
     friend struct HalManifest;
diff --git a/include/vintf/MatrixHal.h b/include/vintf/MatrixHal.h
index e8c4a2a..5a4ccf0 100644
--- a/include/vintf/MatrixHal.h
+++ b/include/vintf/MatrixHal.h
@@ -38,6 +38,8 @@
     std::vector<VersionRange> versionRanges;
     bool optional = false;
     std::map<std::string, HalInterface> interfaces;
+
+    inline const std::string& getName() const { return name; }
 };
 
 } // namespace vintf