Instance is the smallest unit of manifests/matrices.

Introduce forEachInstance on HalManifest and CompatibilityMatrix,
because <hal> are no longer the smallest unit of tests, but
rather a ManifestInstance / MatrixInstance object.

Bug: 73556059
Bug: 74247301

Test: libvintf_test
Test: vintf_object_test

Change-Id: If7186617db52acd67f255ac6e6c99f34a7570206
Merged-In: If7186617db52acd67f255ac6e6c99f34a7570206
diff --git a/Android.bp b/Android.bp
index 1c7a420..03267a5 100644
--- a/Android.bp
+++ b/Android.bp
@@ -38,7 +38,9 @@
         "KernelConfigParser.cpp",
         "RuntimeInfo.cpp",
         "ManifestHal.cpp",
+        "ManifestInstance.cpp",
         "MatrixHal.cpp",
+        "MatrixInstance.cpp",
         "MatrixKernel.cpp",
         "SystemSdk.cpp",
         "TransportArch.cpp",
@@ -48,6 +50,7 @@
     ],
     shared_libs: [
         "libbase",
+        "libhidl-gen-utils",
         "liblog",
         "libselinux",
         "libtinyxml2",
@@ -56,6 +59,10 @@
     export_include_dirs: ["include", "."],
     local_include_dirs: ["include/vintf"],
 
+    export_shared_lib_headers: [
+        "libhidl-gen-utils",
+    ],
+
     target: {
         host: {
             srcs: [
@@ -78,6 +85,7 @@
     defaults: ["libvintf-defaults"],
     shared_libs: [
         "libbase",
+        "libhidl-gen-utils",
         "liblog",
         "libselinux",
         "libtinyxml2",
@@ -90,6 +98,10 @@
         "utils.cpp",
     ],
 
+    export_shared_lib_headers: [
+        "libhidl-gen-utils",
+    ],
+
     whole_static_libs: ["libvintf_common"],
 }
 
@@ -98,6 +110,7 @@
     defaults: ["libvintf-defaults"],
     shared_libs: [
         "libbase",
+        "libhidl-gen-utils",
         "libvintf",
     ],
     srcs: [
@@ -109,6 +122,7 @@
     name: "checkvintf",
     defaults: ["libvintf-defaults"],
     static_libs: [
+        "libhidl-gen-utils",
         "libvintf_common",
         "libutils",
         "libtinyxml2",
diff --git a/Android.mk b/Android.mk
index b7b2ec0..efe2bea 100644
--- a/Android.mk
+++ b/Android.mk
@@ -23,5 +23,9 @@
 LOCAL_STATIC_LIBRARIES := \
     libbase \
     libvintf \
+    libhidl-gen-utils \
     libfs_mgr
+
+LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := libhidl-gen-utils
+
 include $(BUILD_STATIC_LIBRARY)
diff --git a/CompatibilityMatrix.cpp b/CompatibilityMatrix.cpp
index deb1fa1..bf83a98 100644
--- a/CompatibilityMatrix.cpp
+++ b/CompatibilityMatrix.cpp
@@ -312,20 +312,19 @@
     return matrix;
 }
 
-void CompatibilityMatrix::forEachInstance(
-    const std::function<void(const std::string&, const VersionRange&, const std::string&,
-                             const std::string&, bool, bool*)>& f) const {
-    bool stop = false;
-    for (const auto& hal : getHals()) {
-        for (const auto& v : hal.versionRanges) {
-            for (const auto& intf : iterateValues(hal.interfaces)) {
-                for (const auto& instance : intf.instances) {
-                    f(hal.name, v, intf.name, instance, hal.optional, &stop);
-                    if (stop) break;
-                }
+bool CompatibilityMatrix::forEachInstanceOfVersion(
+    const std::string& package, const Version& expectVersion,
+    const std::function<bool(const MatrixInstance&)>& func) const {
+    for (const MatrixHal* hal : getHals(package)) {
+        bool cont = hal->forEachInstance([&](const MatrixInstance& matrixInstance) {
+            if (matrixInstance.versionRange().contains(expectVersion)) {
+                return func(matrixInstance);
             }
-        }
+            return true;
+        });
+        if (!cont) return false;
     }
+    return true;
 }
 
 } // namespace vintf
diff --git a/HalManifest.cpp b/HalManifest.cpp
index 6f05cab..af163ee 100644
--- a/HalManifest.cpp
+++ b/HalManifest.cpp
@@ -184,20 +184,19 @@
     return instances.find(instanceName) != instances.end();
 }
 
-void HalManifest::forEachInstance(
-    const std::function<void(const std::string&, const Version&, const std::string&,
-                             const std::string&, bool*)>& f) const {
-    bool stop = false;
-    for (const auto& hal : getHals()) {
-        for (const auto& v : hal.versions) {
-            for (const auto& intf : iterateValues(hal.interfaces)) {
-                for (const auto& instance : intf.instances) {
-                    f(hal.name, v, intf.name, instance, &stop);
-                    if (stop) break;
-                }
+bool HalManifest::forEachInstanceOfVersion(
+    const std::string& package, const Version& expectVersion,
+    const std::function<bool(const ManifestInstance&)>& func) const {
+    for (const ManifestHal* hal : getHals(package)) {
+        bool cont = hal->forEachInstance([&](const ManifestInstance& manifestInstance) {
+            if (manifestInstance.version().minorAtLeast(expectVersion)) {
+                return func(manifestInstance);
             }
-        }
+            return true;
+        });
+        if (!cont) return false;
     }
+    return true;
 }
 
 static bool satisfyVersion(const MatrixHal& matrixHal, const Version& manifestHalVersion) {
diff --git a/ManifestHal.cpp b/ManifestHal.cpp
index 00d0d95..beffa4d 100644
--- a/ManifestHal.cpp
+++ b/ManifestHal.cpp
@@ -17,6 +17,8 @@
 #include "ManifestHal.h"
 #include <unordered_set>
 
+#include "MapValueIterator.h"
+
 namespace android {
 namespace vintf {
 
@@ -42,13 +44,6 @@
     return true;
 }
 
-bool ManifestHal::containsVersion(const Version& version) const {
-    for (Version v : versions) {
-        if (v.minorAtLeast(version)) return true;
-    }
-    return false;
-}
-
 std::set<std::string> ManifestHal::getInstances(const std::string& interfaceName) const {
     std::set<std::string> ret;
     auto it = interfaces.find(interfaceName);
@@ -58,5 +53,24 @@
     return ret;
 }
 
+bool ManifestHal::forEachInstance(const std::function<bool(const ManifestInstance&)>& func) const {
+    // TODO(b/73556059): support <fqname> as well.
+    for (const auto& v : versions) {
+        for (const auto& intf : iterateValues(interfaces)) {
+            for (const auto& instance : intf.instances) {
+                // TODO(b/73556059): Store ManifestInstance as well to avoid creating temps
+                FqInstance fqInstance;
+                if (fqInstance.setTo(getName(), v.majorVer, v.minorVer, intf.name, instance)) {
+                    if (!func(ManifestInstance(std::move(fqInstance),
+                                               TransportArch{transportArch}))) {
+                        return false;
+                    }
+                }
+            }
+        }
+    }
+    return true;
+}
+
 } // namespace vintf
 } // namespace android
diff --git a/ManifestInstance.cpp b/ManifestInstance.cpp
new file mode 100644
index 0000000..66e0cd3
--- /dev/null
+++ b/ManifestInstance.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ManifestInstance.h"
+
+#include <utility>
+
+namespace android {
+namespace vintf {
+
+ManifestInstance::ManifestInstance(FqInstance&& fqInstance, TransportArch&& ta)
+    : mFqInstance(std::move(fqInstance)), mTransportArch(std::move(ta)) {}
+ManifestInstance::ManifestInstance(const FqInstance& fqInstance, const TransportArch& ta)
+    : mFqInstance(fqInstance), mTransportArch(ta) {}
+
+const std::string& ManifestInstance::package() const {
+    return mFqInstance.getPackage();
+}
+
+Version ManifestInstance::version() const {
+    return mFqInstance.getVersion();
+}
+
+const std::string& ManifestInstance::interface() const {
+    return mFqInstance.getInterface();
+}
+
+const std::string& ManifestInstance::instance() const {
+    return mFqInstance.getInstance();
+}
+
+Transport ManifestInstance::transport() const {
+    return mTransportArch.transport;
+}
+
+Arch ManifestInstance::arch() const {
+    return mTransportArch.arch;
+}
+
+}  // namespace vintf
+}  // namespace android
diff --git a/MatrixHal.cpp b/MatrixHal.cpp
index 96dcf78..fbe9a5f 100644
--- a/MatrixHal.cpp
+++ b/MatrixHal.cpp
@@ -16,6 +16,8 @@
 
 #include "MatrixHal.h"
 
+#include "MapValueIterator.h"
+
 namespace android {
 namespace vintf {
 
@@ -66,5 +68,22 @@
     return true;
 }
 
+bool MatrixHal::forEachInstance(const std::function<bool(const MatrixInstance&)>& func) const {
+    for (const auto& vr : versionRanges) {
+        for (const auto& intf : iterateValues(interfaces)) {
+            for (const auto& instance : intf.instances) {
+                // TODO(b/73556059): Store MatrixInstance as well to avoid creating temps
+                FqInstance fqInstance;
+                if (fqInstance.setTo(getName(), vr.majorVer, vr.minMinor, intf.name, instance)) {
+                    if (!func(MatrixInstance(std::move(fqInstance), VersionRange(vr), optional))) {
+                        return false;
+                    }
+                }
+            }
+        }
+    }
+    return true;
+}
+
 } // namespace vintf
 } // namespace android
diff --git a/MatrixInstance.cpp b/MatrixInstance.cpp
new file mode 100644
index 0000000..46c92e0
--- /dev/null
+++ b/MatrixInstance.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MatrixInstance.h"
+
+#include <utility>
+
+namespace android {
+namespace vintf {
+
+MatrixInstance::MatrixInstance(FqInstance&& fqInstance, VersionRange&& range, bool optional)
+    : mFqInstance(std::move(fqInstance)), mRange(std::move(range)), mOptional(optional) {}
+
+MatrixInstance::MatrixInstance(const FqInstance fqInstance, const VersionRange& range,
+                               bool optional)
+    : mFqInstance(fqInstance), mRange(range), mOptional(optional) {}
+
+const std::string& MatrixInstance::package() const {
+    return mFqInstance.getPackage();
+}
+
+const VersionRange& MatrixInstance::versionRange() const {
+    return mRange;
+}
+
+const std::string& MatrixInstance::interface() const {
+    return mFqInstance.getInterface();
+}
+
+const std::string& MatrixInstance::instance() const {
+    return mFqInstance.getInstance();
+}
+
+bool MatrixInstance::optional() const {
+    return mOptional;
+}
+
+}  // namespace vintf
+}  // namespace android
diff --git a/VintfObject.cpp b/VintfObject.cpp
index c10949c..254a0dc 100644
--- a/VintfObject.cpp
+++ b/VintfObject.cpp
@@ -691,25 +691,23 @@
 }
 
 int32_t VintfObject::CheckDeprecation(std::string* error) {
+    using namespace std::placeholders;
     auto deviceManifest = GetDeviceHalManifest();
     IsInstanceInUse inManifest = [&deviceManifest](const std::string& package, Version version,
-                                                    const std::string& interface,
-                                                    const std::string& instance) {
-        const ManifestHal* hal = deviceManifest->getHal(package, version);
-        if (hal == nullptr) {
-            return std::make_pair(false, Version{});
-        }
-        const auto& instances = hal->getInstances(interface);
-        if (instances.find(instance) == instances.end()) {
-            return std::make_pair(false, Version{});
-        }
-
-        for (Version v : hal->versions) {
-            if (v.minorAtLeast(version)) {
-                return std::make_pair(true, v);
-            }
-        }
-        return std::make_pair(false, Version{});
+                                                   const std::string& interface,
+                                                   const std::string& instance) {
+        std::pair<bool, Version> ret(false, Version{});
+        deviceManifest->forEachInstanceOfInterface(
+            package, version, interface,
+            [&instance, &ret](const ManifestInstance& manifestInstance) {
+                if (manifestInstance.instance() == instance) {
+                    ret.first = true;
+                    ret.second = manifestInstance.version();
+                    return false;
+                }
+                return true;
+            });
+        return ret;
     };
     return CheckDeprecation(inManifest, error);
 }
diff --git a/include/vintf/CompatibilityMatrix.h b/include/vintf/CompatibilityMatrix.h
index 9fcaffc..e31917f 100644
--- a/include/vintf/CompatibilityMatrix.h
+++ b/include/vintf/CompatibilityMatrix.h
@@ -26,6 +26,7 @@
 #include "Level.h"
 #include "MapValueIterator.h"
 #include "MatrixHal.h"
+#include "MatrixInstance.h"
 #include "MatrixKernel.h"
 #include "Named.h"
 #include "SchemaType.h"
@@ -58,9 +59,9 @@
     // (Normally, version ranges do not overlap, and the only match is returned.)
     std::string getXmlSchemaPath(const std::string& xmlFileName, const Version& version) const;
 
-    void forEachInstance(
-        const std::function<void(const std::string&, const VersionRange&, const std::string&,
-                                 const std::string&, bool, bool*)>& f) const;
+    bool forEachInstanceOfVersion(
+        const std::string& package, const Version& expectVersion,
+        const std::function<bool(const MatrixInstance&)>& func) const override;
 
    private:
     bool add(MatrixHal &&hal);
diff --git a/include/vintf/HalGroup.h b/include/vintf/HalGroup.h
index 10c1eae..bb84423 100644
--- a/include/vintf/HalGroup.h
+++ b/include/vintf/HalGroup.h
@@ -20,6 +20,8 @@
 #include <map>
 #include <set>
 
+#include <hidl-util/FqInstance.h>
+
 #include "MapValueIterator.h"
 #include "Version.h"
 
@@ -30,6 +32,8 @@
 // Hal.getName() must return a string indicating the name.
 template <typename Hal>
 struct HalGroup {
+    using InstanceType = typename Hal::InstanceType;
+
    public:
     virtual ~HalGroup() {}
     // Move all hals from another HalGroup to this.
@@ -57,6 +61,7 @@
 
     // Get all hals with the given name (e.g "android.hardware.camera").
     // There could be multiple hals that matches the same given name.
+    // TODO(b/74247301) Deprecated; use forEachInstance instead.
     std::vector<const Hal*> getHals(const std::string& name) const {
         std::vector<const Hal*> ret;
         auto range = mHals.equal_range(name);
@@ -69,6 +74,7 @@
     // Get all hals with the given name (e.g "android.hardware.camera").
     // There could be multiple hals that matches the same given name.
     // Non-const version of the above getHals() method.
+    // TODO(b/74247301) Deprecated; use forEachInstance instead.
     std::vector<Hal*> getHals(const std::string& name) {
         std::vector<Hal*> ret;
         auto range = mHals.equal_range(name);
@@ -78,29 +84,65 @@
         return ret;
     }
 
-    // Get the hal that matches the given name and version (e.g.
-    // "android.hardware.camera@2.4")
-    // There should be a single hal that matches the given name and version.
-    const Hal* getHal(const std::string& name, const Version& version) const {
-        for (const Hal* hal : getHals(name)) {
-            if (hal->containsVersion(version)) return hal;
+    // Apply func to all instances.
+    bool forEachInstance(const std::function<bool(const InstanceType&)>& func) const {
+        for (const auto& hal : getHals()) {
+            bool cont = hal.forEachInstance(func);
+            if (!cont) return false;
         }
-        return nullptr;
+        return true;
     }
 
-    // Get all instance names for hal that matches the given component name, version
-    // and interface name (e.g. "android.hardware.camera@2.4::ICameraProvider").
-    // * If the component ("android.hardware.camera@2.4") does not exist, return empty set.
-    // * If the component ("android.hardware.camera@2.4") does exist,
-    //    * If the interface (ICameraProvider) does not exist, return empty set.
-    //    * Else return the list hal.interface.instance.
+    // Apply func to all instances of package@expectVersion::*/*.
+    // For example, if a.h.foo@1.1::IFoo/default is in "this" and getFqInstances
+    // is called with a.h.foo@1.0, then a.h.foo@1.1::IFoo/default is returned.
+    virtual bool forEachInstanceOfVersion(
+        const std::string& package, const Version& expectVersion,
+        const std::function<bool(const InstanceType&)>& func) const = 0;
+
+    // Apply func to instances of package@expectVersion::interface/*.
+    // For example, if a.h.foo@1.1::IFoo/default is in "this" and getFqInstances
+    // is called with a.h.foo@1.0::IFoo, then a.h.foo@1.1::IFoo/default is returned.
+    bool forEachInstanceOfInterface(const std::string& package, const Version& expectVersion,
+                                    const std::string& interface,
+                                    const std::function<bool(const InstanceType&)>& func) const {
+        return forEachInstanceOfVersion(package, expectVersion,
+                                        [&func, &interface](const InstanceType& e) {
+                                            if (e.interface() == interface) {
+                                                return func(e);
+                                            }
+                                            return true;
+                                        });
+    }
+
+    // Alternative to forEachInstanceOfInterface if you need a vector instead.
+    // If interface is empty, returns all instances of package@version;
+    // else return all instances of package@version::interface.
+    std::vector<InstanceType> getFqInstances(const std::string& package,
+                                             const Version& expectVersion,
+                                             const std::string& interface = "") const {
+        std::vector<InstanceType> v;
+        auto mapToVector = [&v](const auto& e) {
+            v.push_back(e);
+            return true;
+        };
+        if (interface.empty()) {
+            (void)forEachInstanceOfVersion(package, expectVersion, mapToVector);
+        } else {
+            (void)forEachInstanceOfInterface(package, expectVersion, interface, mapToVector);
+        }
+        return v;
+    }
+
+    // Alternative to forEachInstance if you just need a set of instance names instead.
     std::set<std::string> getInstances(const std::string& halName, const Version& version,
                                        const std::string& interfaceName) const {
-        const Hal* hal = getHal(halName, version);
-        if (hal == nullptr) {
-            return {};
-        }
-        return hal->getInstances(interfaceName);
+        std::set<std::string> ret;
+        (void)forEachInstanceOfInterface(halName, version, interfaceName, [&ret](const auto& e) {
+            ret.insert(e.instance());
+            return true;
+        });
+        return ret;
     }
 
    protected:
diff --git a/include/vintf/HalManifest.h b/include/vintf/HalManifest.h
index e497d42..71f7017 100644
--- a/include/vintf/HalManifest.h
+++ b/include/vintf/HalManifest.h
@@ -18,14 +18,16 @@
 #ifndef ANDROID_VINTF_HAL_MANIFEST_H
 #define ANDROID_VINTF_HAL_MANIFEST_H
 
+#include <hidl-util/FqInstance.h>
+#include <utils/Errors.h>
 #include <map>
 #include <string>
-#include <utils/Errors.h>
 #include <vector>
 
 #include "HalGroup.h"
 #include "Level.h"
 #include "ManifestHal.h"
+#include "ManifestInstance.h"
 #include "MapValueIterator.h"
 #include "SchemaType.h"
 #include "SystemSdk.h"
@@ -117,9 +119,9 @@
     // Get metaversion of this manifest.
     Version getMetaVersion() const;
 
-    void forEachInstance(
-        const std::function<void(const std::string&, const Version&, const std::string&,
-                                 const std::string&, bool*)>& f) const;
+    bool forEachInstanceOfVersion(
+        const std::string& package, const Version& expectVersion,
+        const std::function<bool(const ManifestInstance&)>& func) const override;
 
    protected:
     // Check before add()
diff --git a/include/vintf/ManifestHal.h b/include/vintf/ManifestHal.h
index e326857..da5a700 100644
--- a/include/vintf/ManifestHal.h
+++ b/include/vintf/ManifestHal.h
@@ -25,6 +25,7 @@
 
 #include "HalFormat.h"
 #include "HalInterface.h"
+#include "ManifestInstance.h"
 #include "TransportArch.h"
 #include "Version.h"
 
@@ -33,6 +34,7 @@
 
 // A component of HalManifest.
 struct ManifestHal {
+    using InstanceType = ManifestInstance;
 
     bool operator==(const ManifestHal &other) const;
     // Check whether the ManifestHal contains the given version.
@@ -57,6 +59,7 @@
     }
 
     inline const std::string& getName() const { return name; }
+    bool forEachInstance(const std::function<bool(const ManifestInstance&)>& func) const;
 
    private:
     friend struct LibVintfTest;
diff --git a/include/vintf/ManifestInstance.h b/include/vintf/ManifestInstance.h
new file mode 100644
index 0000000..a2a89ef
--- /dev/null
+++ b/include/vintf/ManifestInstance.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_VINTF_MANIFEST_INSTANCE_H
+#define ANDROID_VINTF_MANIFEST_INSTANCE_H
+
+#include <string>
+
+#include <hidl-util/FqInstance.h>
+
+#include "TransportArch.h"
+#include "Version.h"
+
+namespace android {
+namespace vintf {
+
+class ManifestInstance {
+   public:
+    using VersionType = Version;
+    ManifestInstance(FqInstance&& fqInstance, TransportArch&& ta);
+    ManifestInstance(const FqInstance& fqInstance, const TransportArch& ta);
+    const std::string& package() const;
+    Version version() const;
+    const std::string& interface() const;
+    const std::string& instance() const;
+    Transport transport() const;
+    Arch arch() const;
+
+   private:
+    FqInstance mFqInstance;
+    TransportArch mTransportArch;
+};
+
+}  // namespace vintf
+}  // namespace android
+
+#endif  // ANDROID_VINTF_MANIFEST_INSTANCE_H
diff --git a/include/vintf/MatrixHal.h b/include/vintf/MatrixHal.h
index 47094fb..29c44c7 100644
--- a/include/vintf/MatrixHal.h
+++ b/include/vintf/MatrixHal.h
@@ -24,6 +24,7 @@
 
 #include "HalFormat.h"
 #include "HalInterface.h"
+#include "MatrixInstance.h"
 #include "VersionRange.h"
 
 namespace android {
@@ -31,6 +32,7 @@
 
 // A HAL entry to a compatibility matrix
 struct MatrixHal {
+    using InstanceType = MatrixInstance;
 
     bool operator==(const MatrixHal &other) const;
     // Check whether the MatrixHal contains the given version.
@@ -51,6 +53,8 @@
 
     // Return true if "this" contains all interface/instance instances in "other".
     bool containsInstances(const MatrixHal& other) const;
+
+    bool forEachInstance(const std::function<bool(const MatrixInstance&)>& func) const;
 };
 
 } // namespace vintf
diff --git a/include/vintf/MatrixInstance.h b/include/vintf/MatrixInstance.h
new file mode 100644
index 0000000..bbd57dc
--- /dev/null
+++ b/include/vintf/MatrixInstance.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_VINTF_MATRIX_INSTANCE_H
+#define ANDROID_VINTF_MATRIX_INSTANCE_H
+
+#include <string>
+
+#include <hidl-util/FqInstance.h>
+
+#include "VersionRange.h"
+
+namespace android {
+namespace vintf {
+
+class MatrixInstance {
+   public:
+    using VersionType = VersionRange;
+    // fqInstance.version is ignored. Version range is provided separately.
+    MatrixInstance(FqInstance&& fqInstance, VersionRange&& range, bool optional);
+    MatrixInstance(const FqInstance fqInstance, const VersionRange& range, bool optional);
+    const std::string& package() const;
+    const VersionRange& versionRange() const;
+    const std::string& interface() const;
+    const std::string& instance() const;
+    bool optional() const;
+
+   private:
+    FqInstance mFqInstance;
+    VersionRange mRange;
+    bool mOptional;
+};
+
+}  // namespace vintf
+}  // namespace android
+
+#endif  // ANDROID_VINTF_MATRIX_INSTANCE_H
diff --git a/include/vintf/Version.h b/include/vintf/Version.h
index 5fab0fa..4531f2e 100644
--- a/include/vintf/Version.h
+++ b/include/vintf/Version.h
@@ -29,6 +29,8 @@
 
     constexpr Version() : Version(0u, 0u) {}
     constexpr Version(size_t mj, size_t mi) : majorVer(mj), minorVer(mi) {}
+    constexpr Version(const std::pair<size_t, size_t>& pair)
+        : majorVer(pair.first), minorVer(pair.second) {}
 
     size_t majorVer;
     size_t minorVer;
diff --git a/main.cpp b/main.cpp
index c4119c9..7843cb5 100644
--- a/main.cpp
+++ b/main.cpp
@@ -188,34 +188,38 @@
 // if it does not exist and setting the corresponding indicator (as specified by "mutate").
 void insert(const HalManifest* manifest, Table* table, const RowMutator& mutate) {
     if (manifest == nullptr) return;
-    manifest->forEachInstance([&](const auto& package, const auto& version, const auto& interface,
-                                  const auto& instance, bool* /* stop */) {
-        std::string key = toFQNameString(package, VersionRange{version.majorVer, version.minorVer},
-                                         interface, instance);
+    manifest->forEachInstance([&](const auto& manifestInstance) {
+        std::string key = toFQNameString(manifestInstance.package(), manifestInstance.version(),
+                                         manifestInstance.interface(), manifestInstance.instance());
         mutate(&(*table)[key]);
+        return true;
     });
 }
 
 void insert(const CompatibilityMatrix* matrix, Table* table, const RowMutator& mutate) {
     if (matrix == nullptr) return;
-    matrix->forEachInstance([&](const auto& package, const auto& range, const auto& interface,
-                                const auto& instance, bool optional, bool* /* stop */) {
+    matrix->forEachInstance([&](const auto& matrixInstance) {
         bool missed = false;
-        for (auto minorVer = range.minMinor; minorVer <= range.maxMinor; ++minorVer) {
-            std::string key = toFQNameString(package, VersionRange{range.majorVer, minorVer},
-                                             interface, instance);
+        for (auto minorVer = matrixInstance.versionRange().minMinor;
+             minorVer <= matrixInstance.versionRange().maxMinor; ++minorVer) {
+            std::string key = toFQNameString(
+                matrixInstance.package(), Version{matrixInstance.versionRange().majorVer, minorVer},
+                matrixInstance.interface(), matrixInstance.instance());
             auto it = table->find(key);
             if (it == table->end()) {
                 missed = true;
             } else {
                 mutate(&it->second);
-                it->second.required = !optional;
+                it->second.required = !matrixInstance.optional();
             }
         }
         if (missed) {
-            std::string key = toFQNameString(package, range, interface, instance);
+            std::string key =
+                toFQNameString(matrixInstance.package(), matrixInstance.versionRange(),
+                               matrixInstance.interface(), matrixInstance.instance());
             mutate(&(*table)[key]);
         }
+        return true;
     });
 }
 
diff --git a/test/Android.bp b/test/Android.bp
index 50afb63..4dd6480 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -31,6 +31,7 @@
     static_libs: [
         "libgtest",
         "libassemblevintf",
+        "libhidl-gen-utils",
     ],
 
     cflags: [
@@ -65,8 +66,8 @@
     static_libs: [
         "libgtest",
         "libgmock",
-        "libhidl-gen-utils",
         "libvintf_common",
+        "libhidl-gen-utils",
         "libz",
     ],
     cflags: [
diff --git a/test/LibVintfTest.cpp b/test/LibVintfTest.cpp
index 33fd833..ee4a3e2 100644
--- a/test/LibVintfTest.cpp
+++ b/test/LibVintfTest.cpp
@@ -758,18 +758,6 @@
     auto nfcHals = vm.getHals("android.hardware.nfc");
     EXPECT_EQ((int)nfcHals.size(), 1);
     EXPECT_EQ(*nfcHals[0], expectedNfcHal);
-
-    EXPECT_EQ(*vm.getHal("android.hardware.camera", {1, 1}), expectedCameraHalV1_2);
-    EXPECT_EQ(*vm.getHal("android.hardware.camera", {2, 0}), expectedCameraHalV2_0);
-    EXPECT_EQ(*vm.getHal("android.hardware.nfc", {1, 0}), expectedNfcHal);
-    EXPECT_EQ(*vm.getHal("android.hardware.nfc", {2, 0}), expectedNfcHal);
-    EXPECT_EQ(*vm.getHal("android.hardware.nfc", {2, 1}), expectedNfcHal);
-
-    EXPECT_EQ(vm.getHal("non-existent", {1, 0}), nullptr);
-    EXPECT_EQ(vm.getHal("android.hardware.camera", {2, 1}), nullptr);
-    EXPECT_EQ(vm.getHal("android.hardware.camera", {1, 3}), nullptr);
-    EXPECT_EQ(vm.getHal("android.hardware.nfc", {1, 1}), nullptr);
-    EXPECT_EQ(vm.getHal("android.hardware.nfc", {3, 0}), nullptr);
 }
 
 TEST_F(LibVintfTest, CompatibilityMatrixGetHals) {
@@ -803,18 +791,6 @@
     auto nfcHals = cm.getHals("android.hardware.nfc");
     EXPECT_EQ((int)nfcHals.size(), 1);
     EXPECT_EQ(*nfcHals[0], expectedNfcHal);
-
-    EXPECT_EQ(*cm.getHal("android.hardware.camera", {1, 2}), expectedCameraHal);
-    EXPECT_EQ(*cm.getHal("android.hardware.camera", {1, 3}), expectedCameraHal);
-    EXPECT_EQ(*cm.getHal("android.hardware.camera", {4, 5}), expectedCameraHal);
-    EXPECT_EQ(*cm.getHal("android.hardware.nfc", {4, 5}), expectedNfcHal);
-    EXPECT_EQ(*cm.getHal("android.hardware.nfc", {10, 12}), expectedNfcHal);
-
-    EXPECT_EQ(cm.getHal("non-existent", {1, 0}), nullptr);
-    EXPECT_EQ(cm.getHal("android.hardware.camera", {2, 1}), nullptr);
-    EXPECT_EQ(cm.getHal("android.hardware.camera", {1, 0}), nullptr);
-    EXPECT_EQ(cm.getHal("android.hardware.nfc", {3, 0}), nullptr);
-    EXPECT_EQ(cm.getHal("android.hardware.nfc", {4, 7}), nullptr);
 }
 
 TEST_F(LibVintfTest, RuntimeInfo) {
@@ -2443,12 +2419,12 @@
         "    </hal>\n"
         "</manifest>\n";
     EXPECT_TRUE(gHalManifestConverter(&manifest, xml)) << gHalManifestConverter.lastError();
-    const ManifestHal* foo = manifest.getHal("android.hardware.foo", {1, 0});
-    ASSERT_NE(nullptr, foo);
-    EXPECT_TRUE(foo->isOverride);
-    const ManifestHal* bar = manifest.getHal("android.hardware.bar", {1, 0});
-    ASSERT_NE(nullptr, bar);
-    EXPECT_FALSE(bar->isOverride);
+    const auto& foo = manifest.getHals("android.hardware.foo");
+    ASSERT_FALSE(foo.empty());
+    EXPECT_TRUE(foo.front()->isOverride);
+    const auto& bar = manifest.getHals("android.hardware.bar");
+    ASSERT_FALSE(bar.empty());
+    EXPECT_FALSE(bar.front()->isOverride);
 }
 
 // Test functionality of override="true" tag