Merge changes from topic "hidl-host-test"

* changes:
  Add hidl-gen-host_test.
  Move hidl_test into its own folder.
  Remove extra '/' from Coordinator paths.
  Coordinator checks for package root conflicts.
diff --git a/Android.bp b/Android.bp
index f9f9a85..6938c25 100644
--- a/Android.bp
+++ b/Android.bp
@@ -98,6 +98,11 @@
         "libhidl-gen-hash",
         "libhidl-gen-utils",
     ],
+    export_shared_lib_headers: [
+        "libbase",
+        "libhidl-gen-utils",
+    ],
+    export_include_dirs: ["."], // for tests
 }
 
 //
@@ -124,6 +129,11 @@
         "libhidl-gen-hash",
         "libhidl-gen-utils",
     ],
+    export_shared_lib_headers: [
+        "libbase",
+        "libhidl-gen-utils",
+    ],
+    export_include_dirs: ["."], // for tests
 }
 
 //
diff --git a/Coordinator.cpp b/Coordinator.cpp
index 8f87e7b..c56d343 100644
--- a/Coordinator.cpp
+++ b/Coordinator.cpp
@@ -42,27 +42,40 @@
 
 namespace android {
 
-Coordinator::Coordinator(
-        const std::vector<std::string> &packageRootPaths,
-        const std::vector<std::string> &packageRoots,
-        const std::string &rootPath)
-    : mPackageRootPaths(packageRootPaths),
-      mPackageRoots(packageRoots),
-      mRootPath(rootPath) {
-    // empty
+const std::string &Coordinator::getRootPath() const {
+    return mRootPath;
 }
 
-Coordinator::~Coordinator() {
-    // empty
-}
+void Coordinator::setRootPath(const std::string &rootPath) {
+    mRootPath = rootPath;
 
-void Coordinator::addDefaultPackagePath(const std::string& root, const std::string& path) {
-    if (std::find(mPackageRoots.begin(), mPackageRoots.end(), root) == mPackageRoots.end()) {
-        mPackageRoots.push_back(root);
-        mPackageRootPaths.push_back(path);
+    if (!mRootPath.empty() && !StringHelper::EndsWith(mRootPath, "/")) {
+        mRootPath += "/";
     }
 }
 
+status_t Coordinator::addPackagePath(const std::string& root, const std::string& path, std::string* error) {
+    FQName package = FQName(root, "0.0", "");
+    for (const PackageRoot &packageRoot : mPackageRoots) {
+        if (packageRoot.root.inPackage(root) || package.inPackage(packageRoot.root.package())) {
+            if (error != nullptr) {
+                *error = "ERROR: conflicting package roots " +
+                         packageRoot.root.package() +
+                         " and " +
+                         root;
+            }
+
+            return UNKNOWN_ERROR;
+        }
+    }
+
+    mPackageRoots.push_back({StringHelper::RTrimAll(path, "/"), package});
+    return OK;
+}
+void Coordinator::addDefaultPackagePath(const std::string& root, const std::string& path) {
+    addPackagePath(root, path, nullptr /* error */);
+}
+
 AST* Coordinator::parse(const FQName& fqName, std::set<AST*>* parsedASTs,
                         Enforce enforcement) const {
     CHECK(fqName.isFullyQualified());
@@ -183,8 +196,7 @@
     return ast;
 }
 
-std::vector<std::string>::const_iterator
-Coordinator::findPackageRoot(const FQName &fqName) const {
+const Coordinator::PackageRoot &Coordinator::findPackageRoot(const FQName &fqName) const {
     CHECK(!fqName.package().empty());
 
     // Find the right package prefix and path for this FQName.  For
@@ -194,23 +206,23 @@
     // prefix "android.hardware" and the package root
     // "hardware/interfaces".
 
-    auto it = mPackageRoots.begin();
     auto ret = mPackageRoots.end();
-    for (; it != mPackageRoots.end(); it++) {
-        if (!fqName.inPackage(*it)) {
+    for (auto it = mPackageRoots.begin(); it != mPackageRoots.end(); it++) {
+        if (!fqName.inPackage(it->root.package())) {
             continue;
         }
 
         CHECK(ret == mPackageRoots.end())
-            << "Multiple package roots found for " << fqName.string()
-            << " (" << *it << " and " << *ret << ")";
+            << "Multiple package roots found for "<< fqName.string()
+            << " (" << it->root.package() << " and "
+            << ret->root.package() << ")";
 
         ret = it;
     }
     CHECK(ret != mPackageRoots.end())
         << "Unable to find package root for " << fqName.string();
 
-    return ret;
+    return *ret;
 }
 
 std::string Coordinator::makeAbsolute(const std::string& path) const {
@@ -218,19 +230,15 @@
         return path;
     }
 
-    return StringHelper::RTrim(mRootPath, "/") + "/" + path;
+    return mRootPath + path;
 }
 
 std::string Coordinator::getPackageRoot(const FQName &fqName) const {
-    auto it = findPackageRoot(fqName);
-    auto prefix = *it;
-    return prefix;
+    return findPackageRoot(fqName).root.package();
 }
 
 std::string Coordinator::getPackageRootPath(const FQName &fqName) const {
-    auto it = findPackageRoot(fqName);
-    auto root = mPackageRootPaths[std::distance(mPackageRoots.begin(), it)];
-    return root;
+    return findPackageRoot(fqName).path;
 }
 
 std::string Coordinator::getPackageRootOption(const FQName &fqName) const {
@@ -238,21 +246,20 @@
 }
 
 std::string Coordinator::getPackagePath(
-        const FQName &fqName, bool relative, bool sanitized) const {
+        const FQName& fqName, bool relative, bool sanitized) const {
 
-    const auto it = findPackageRoot(fqName);
-    const std::string prefix = *it;
+    const PackageRoot& packageRoot = findPackageRoot(fqName);
 
     // Given FQName of "android.hardware.nfc.test@1.0::IFoo" and a prefix
     // "android.hardware", the suffix is "nfc.test".
-    const std::string suffix = StringHelper::LTrim(fqName.package(), prefix + ".");
+    const std::string suffix = StringHelper::LTrim(
+        fqName.package(), packageRoot.root.package() + ".");
     std::vector<std::string> suffixComponents;
     StringHelper::SplitString(suffix, '.', &suffixComponents);
 
     std::vector<std::string> components;
     if (!relative) {
-        const std::string rootPath = mPackageRootPaths[std::distance(mPackageRoots.begin(), it)];
-        components.push_back(rootPath);
+        components.push_back(packageRoot.path);
     }
     components.insert(components.end(), suffixComponents.begin(), suffixComponents.end());
     components.push_back(sanitized ? fqName.sanitizedVersion() : fqName.version());
diff --git a/Coordinator.h b/Coordinator.h
index ed1a81f..21106f8 100644
--- a/Coordinator.h
+++ b/Coordinator.h
@@ -19,6 +19,7 @@
 #define COORDINATOR_H_
 
 #include <android-base/macros.h>
+#include <hidl-util/FQName.h>
 #include <map>
 #include <set>
 #include <string>
@@ -28,18 +29,17 @@
 namespace android {
 
 struct AST;
-struct FQName;
 struct Type;
 
 struct Coordinator {
-    Coordinator(
-            const std::vector<std::string> &packageRootPaths,
-            const std::vector<std::string> &packageRoots,
-            const std::string &rootPath);
+    Coordinator() {};
 
-    ~Coordinator();
+    const std::string &getRootPath() const;
+    void setRootPath(const std::string &rootPath);
 
     // adds path only if it doesn't exist
+    status_t addPackagePath(const std::string& root, const std::string& path, std::string* error);
+    // adds path if it hasn't already been added
     void addDefaultPackagePath(const std::string& root, const std::string& path);
 
     enum class Enforce {
@@ -105,14 +105,12 @@
     static bool MakeParentHierarchy(const std::string &path);
 
 private:
-    // A list of top-level directories (mPackageRootPaths)
-    // corresponding to a list of package roots (mPackageRoots). For
-    // example, if mPackageRootPaths[0] == "hardware/interfaces" and
-    // mPackageRoots[0] == "android.hardware" this means that all
-    // packages starting with "android.hardware" will be looked up in
-    // "hardware/interfaces".
-    std::vector<std::string> mPackageRootPaths;
-    std::vector<std::string> mPackageRoots;
+    // indicates that packages in "android.hardware" will be looked up in hardware/interfaces
+    struct PackageRoot {
+        std::string path; // e.x. hardware/interfaces
+        FQName root; // e.x. android.hardware@0.0
+    };
+    std::vector<PackageRoot> mPackageRoots;
 
     std::string mRootPath;
 
@@ -122,8 +120,7 @@
     // cache to enforceRestrictionsOnPackage().
     mutable std::set<FQName> mPackagesEnforced;
 
-    std::vector<std::string>::const_iterator findPackageRoot(
-            const FQName &fqName) const;
+    const PackageRoot &findPackageRoot(const FQName &fqName) const;
 
     // Returns the given path if it is absolute, otherwise it returns
     // the path relative to mRootPath
diff --git a/main.cpp b/main.cpp
index 3969b11..53353e6 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1317,25 +1317,27 @@
 }
 
 int main(int argc, char **argv) {
-    std::string outputPath;
-    std::string rootPath;
-    std::vector<std::string> packageRootPaths;
-    std::vector<std::string> packageRoots;
-
     const char *me = argv[0];
-    OutputHandler *outputFormat = nullptr;
-
     if (argc == 1) {
         usage(me);
         exit(1);
     }
 
+    OutputHandler *outputFormat = nullptr;
+    Coordinator coordinator;
+    std::string outputPath;
+
+    const char *ANDROID_BUILD_TOP = getenv("ANDROID_BUILD_TOP");
+    if (ANDROID_BUILD_TOP != nullptr) {
+        coordinator.setRootPath(ANDROID_BUILD_TOP);
+    }
+
     int res;
     while ((res = getopt(argc, argv, "hp:o:r:L:t")) >= 0) {
         switch (res) {
             case 'p':
             {
-                rootPath = optarg;
+                coordinator.setRootPath(optarg);
                 break;
             }
 
@@ -1354,10 +1356,16 @@
                     exit(1);
                 }
 
-                auto package = val.substr(0, index);
+                auto root = val.substr(0, index);
                 auto path = val.substr(index + 1);
-                packageRootPaths.push_back(path);
-                packageRoots.push_back(package);
+
+                std::string error;
+                status_t err = coordinator.addPackagePath(root, path, &error);
+                if (err != OK) {
+                    fprintf(stderr, "%s\n", error.c_str());
+                    exit(1);
+                }
+
                 break;
             }
 
@@ -1420,20 +1428,6 @@
         exit(1);
     }
 
-    if (rootPath.empty()) {
-        const char *ANDROID_BUILD_TOP = getenv("ANDROID_BUILD_TOP");
-
-        if (ANDROID_BUILD_TOP != nullptr) {
-            rootPath = ANDROID_BUILD_TOP;
-        }
-
-        // else default to pwd
-    }
-
-    if (!rootPath.empty() && !StringHelper::EndsWith(rootPath, "/")) {
-        rootPath += "/";
-    }
-
     // Valid options are now in argv[0] .. argv[argc - 1].
 
     switch (outputFormat->mOutputMode) {
@@ -1455,7 +1449,7 @@
         case OutputHandler::NEEDS_SRC:
         {
             if (outputPath.empty()) {
-                outputPath = rootPath;
+                outputPath = coordinator.getRootPath();
             }
             if (outputPath.back() != '/') {
                 outputPath += "/";
@@ -1469,7 +1463,6 @@
             break;
     }
 
-    Coordinator coordinator(packageRootPaths, packageRoots, rootPath);
     coordinator.addDefaultPackagePath("android.hardware", "hardware/interfaces");
     coordinator.addDefaultPackagePath("android.hidl", "system/libhidl/transport");
     coordinator.addDefaultPackagePath("android.frameworks", "frameworks/hardware/interfaces");
diff --git a/test/Android.bp b/test/Android.bp
index f6347f7..2cbc049 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -1,6 +1,8 @@
 subdirs = [
     "error_test",
     "hash_test",
+    "hidl_test",
+    "host_test",
     "impl_test",
     "java_test",
     "utils_test",
@@ -8,78 +10,3 @@
     "vendor/1.1",
     "version_test",
 ]
-
-cc_test {
-    name: "hidl_test_client",
-    defaults: ["hidl-gen-defaults"],
-    srcs: ["hidl_test_client.cpp", "FooCallback.cpp", "static_test.cpp"],
-
-    shared_libs: [
-        "libbase",
-        "liblog",
-        "libcutils",
-        "libhidlbase",
-        "libhidltransport",
-        "libhidlmemory",
-        "libfootest",
-        "libhwbinder",
-        "libpointertest",
-        "libutils",
-        "android.hardware.tests.expression@1.0",
-        "android.hardware.tests.foo@1.0",
-        "android.hardware.tests.bar@1.0",
-        "android.hardware.tests.baz@1.0",
-        "android.hardware.tests.hash@1.0",
-        "android.hardware.tests.inheritance@1.0",
-        "android.hardware.tests.pointer@1.0",
-        "android.hardware.tests.memory@1.0",
-        "android.hardware.tests.multithread@1.0",
-        "android.hardware.tests.trie@1.0",
-        "android.hidl.allocator@1.0",
-        "android.hidl.memory@1.0",
-        "android.hidl.token@1.0",
-    ],
-
-    required: [
-        // Warning, these should never be specified explicitly for anything else
-        // as for a given device, what hal implementation is used is determined
-        // by what is specified/available in a device.mk. However, this test
-        // actually depends on these test implementations (which should never be
-        // included on a device.mk).
-        "android.hardware.tests.foo@1.0-impl",
-        "android.hardware.tests.bar@1.0-impl",
-        "android.hardware.tests.baz@1.0-impl",
-        "android.hardware.tests.hash@1.0-impl",
-        "android.hardware.tests.inheritance@1.0-impl",
-        "android.hardware.tests.pointer@1.0-impl",
-        "android.hardware.tests.memory@1.0-impl",
-        "android.hardware.tests.multithread@1.0-impl",
-        "android.hardware.tests.trie@1.0-impl",
-    ],
-}
-
-cc_test {
-    name: "hidl_test_servers",
-    srcs: ["hidl_test_servers.cpp"],
-    gtest: false,
-
-    shared_libs: [
-        "libbase",
-        "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
-        "liblog",
-        "libutils",
-        "android.hardware.tests.foo@1.0",
-        "android.hardware.tests.bar@1.0",
-        "android.hardware.tests.baz@1.0",
-        "android.hardware.tests.hash@1.0",
-        "android.hardware.tests.inheritance@1.0",
-        "android.hardware.tests.pointer@1.0",
-        "android.hardware.tests.memory@1.0",
-        "android.hardware.tests.multithread@1.0",
-        "android.hardware.tests.trie@1.0",
-        "android.hidl.memory@1.0",
-        "android.hidl.token@1.0",
-    ],
-}
diff --git a/test/hidl_test/Android.bp b/test/hidl_test/Android.bp
new file mode 100644
index 0000000..7ab6c39
--- /dev/null
+++ b/test/hidl_test/Android.bp
@@ -0,0 +1,74 @@
+cc_test {
+    name: "hidl_test_client",
+    defaults: ["hidl-gen-defaults"],
+    srcs: ["hidl_test_client.cpp", "FooCallback.cpp", "static_test.cpp"],
+
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libcutils",
+        "libhidlbase",
+        "libhidltransport",
+        "libhidlmemory",
+        "libfootest",
+        "libhwbinder",
+        "libpointertest",
+        "libutils",
+        "android.hardware.tests.expression@1.0",
+        "android.hardware.tests.foo@1.0",
+        "android.hardware.tests.bar@1.0",
+        "android.hardware.tests.baz@1.0",
+        "android.hardware.tests.hash@1.0",
+        "android.hardware.tests.inheritance@1.0",
+        "android.hardware.tests.pointer@1.0",
+        "android.hardware.tests.memory@1.0",
+        "android.hardware.tests.multithread@1.0",
+        "android.hardware.tests.trie@1.0",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "android.hidl.token@1.0",
+    ],
+
+    required: [
+        // Warning, these should never be specified explicitly for anything else
+        // as for a given device, what hal implementation is used is determined
+        // by what is specified/available in a device.mk. However, this test
+        // actually depends on these test implementations (which should never be
+        // included on a device.mk).
+        "android.hardware.tests.foo@1.0-impl",
+        "android.hardware.tests.bar@1.0-impl",
+        "android.hardware.tests.baz@1.0-impl",
+        "android.hardware.tests.hash@1.0-impl",
+        "android.hardware.tests.inheritance@1.0-impl",
+        "android.hardware.tests.pointer@1.0-impl",
+        "android.hardware.tests.memory@1.0-impl",
+        "android.hardware.tests.multithread@1.0-impl",
+        "android.hardware.tests.trie@1.0-impl",
+    ],
+}
+
+cc_test {
+    name: "hidl_test_servers",
+    srcs: ["hidl_test_servers.cpp"],
+    gtest: false,
+
+    shared_libs: [
+        "libbase",
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "liblog",
+        "libutils",
+        "android.hardware.tests.foo@1.0",
+        "android.hardware.tests.bar@1.0",
+        "android.hardware.tests.baz@1.0",
+        "android.hardware.tests.hash@1.0",
+        "android.hardware.tests.inheritance@1.0",
+        "android.hardware.tests.pointer@1.0",
+        "android.hardware.tests.memory@1.0",
+        "android.hardware.tests.multithread@1.0",
+        "android.hardware.tests.trie@1.0",
+        "android.hidl.memory@1.0",
+        "android.hidl.token@1.0",
+    ],
+}
diff --git a/test/Android.mk b/test/hidl_test/Android.mk
similarity index 96%
rename from test/Android.mk
rename to test/hidl_test/Android.mk
index ff0001c..43d7102 100644
--- a/test/Android.mk
+++ b/test/hidl_test/Android.mk
@@ -39,5 +39,3 @@
 LOCAL_MODULE := VtsHidlUnitTests
 VTS_CONFIG_SRC_DIR := system/tools/hidl/tests
 -include test/vts/tools/build/Android.host_config.mk
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/test/AndroidTest.xml b/test/hidl_test/AndroidTest.xml
similarity index 100%
rename from test/AndroidTest.xml
rename to test/hidl_test/AndroidTest.xml
diff --git a/test/FooCallback.cpp b/test/hidl_test/FooCallback.cpp
similarity index 100%
rename from test/FooCallback.cpp
rename to test/hidl_test/FooCallback.cpp
diff --git a/test/FooCallback.h b/test/hidl_test/FooCallback.h
similarity index 100%
rename from test/FooCallback.h
rename to test/hidl_test/FooCallback.h
diff --git a/test/hidl_test b/test/hidl_test/hidl_test
similarity index 100%
rename from test/hidl_test
rename to test/hidl_test/hidl_test
diff --git a/test/hidl_test.h b/test/hidl_test/hidl_test.h
similarity index 100%
rename from test/hidl_test.h
rename to test/hidl_test/hidl_test.h
diff --git a/test/hidl_test_client.cpp b/test/hidl_test/hidl_test_client.cpp
similarity index 100%
rename from test/hidl_test_client.cpp
rename to test/hidl_test/hidl_test_client.cpp
diff --git a/test/hidl_test_helper b/test/hidl_test/hidl_test_helper
similarity index 100%
rename from test/hidl_test_helper
rename to test/hidl_test/hidl_test_helper
diff --git a/test/hidl_test_servers.cpp b/test/hidl_test/hidl_test_servers.cpp
similarity index 100%
rename from test/hidl_test_servers.cpp
rename to test/hidl_test/hidl_test_servers.cpp
diff --git a/test/static_test.cpp b/test/hidl_test/static_test.cpp
similarity index 100%
rename from test/static_test.cpp
rename to test/hidl_test/static_test.cpp
diff --git a/test/host_test/Android.bp b/test/host_test/Android.bp
new file mode 100644
index 0000000..d5e6511
--- /dev/null
+++ b/test/host_test/Android.bp
@@ -0,0 +1,26 @@
+// Copyright (C) 2017 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.
+
+cc_test_host {
+    name: "hidl-gen-host_test",
+    defaults: ["hidl-gen-defaults"],
+
+    shared_libs: [
+        "libhidl-gen",
+        "libhidl-gen-ast",
+        "libhidl-gen-utils",
+    ],
+
+    srcs: ["main.cpp"],
+}
\ No newline at end of file
diff --git a/test/host_test/main.cpp b/test/host_test/main.cpp
new file mode 100644
index 0000000..2709392
--- /dev/null
+++ b/test/host_test/main.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "libhidl-gen-utils"
+
+#include <gtest/gtest.h>
+
+#include <Coordinator.h>
+#include <ConstantExpression.h>
+
+namespace android {
+
+class HidlGenHostTest : public ::testing::Test {};
+
+TEST_F(HidlGenHostTest, CoordinatorTest) {
+    Coordinator coordinator;
+
+    std::string error;
+    EXPECT_EQ(OK, coordinator.addPackagePath("a.b", "a1/b1", &error));
+    EXPECT_TRUE(error.empty());
+    EXPECT_NE(OK, coordinator.addPackagePath("a.b", "a2/b2/", &error));
+    EXPECT_FALSE(error.empty());
+
+    coordinator.addDefaultPackagePath("a.b", "a3/b3/"); // should take path above
+    coordinator.addDefaultPackagePath("a.c", "a4/b4/"); // should succeed
+
+    EXPECT_EQ("a1/b1/foo/1.0/", coordinator.getPackagePath(FQName("a.b.foo@1.0")));
+    EXPECT_EQ("a4/b4/foo/bar/1.0/", coordinator.getPackagePath(FQName("a.c.foo.bar@1.0::IFoo")));
+
+    EXPECT_EQ("a.b", coordinator.getPackageRoot(FQName("a.b.foo@1.0")));
+    EXPECT_EQ("a.c", coordinator.getPackageRoot(FQName("a.c.foo.bar@1.0::IFoo")));
+
+    EXPECT_EQ("foo/1.0/", coordinator.getPackagePath(FQName("a.b.foo@1.0"), true /* relative */));
+    EXPECT_EQ("foo/bar/1.0/", coordinator.getPackagePath(FQName("a.c.foo.bar@1.0::IFoo"), true /* relative */));
+}
+
+TEST_F(HidlGenHostTest, LocationTest) {
+    Location a{{"file", 3, 4}, {"file", 3, 5}};
+    Location b{{"file", 3, 6}, {"file", 3, 7}};
+    Location c{{"file", 4, 4}, {"file", 4, 5}};
+
+    Location other{{"other", 0, 0}, {"other", 0, 1}};
+
+    EXPECT_LT(a, b);
+    EXPECT_LT(b, c);
+    EXPECT_LT(a, c);
+    EXPECT_FALSE(Location::inSameFile(a, other));
+}
+
+int main(int argc, char **argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}
+
+}  // namespace android
\ No newline at end of file
diff --git a/test/run_all_host_tests.sh b/test/run_all_host_tests.sh
index 25ffc10..0a69a7a 100755
--- a/test/run_all_host_tests.sh
+++ b/test/run_all_host_tests.sh
@@ -1,11 +1,41 @@
 #!/bin/bash
 
-$ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode -j \
-    hidl_error_test \
-    hidl_hash_test \
-    hidl_impl_test \
-    libhidl-gen-utils_test &&
+function run() {
+    local FAILED_TESTS=()
 
-$ANDROID_BUILD_TOP/out/host/linux-x86/nativetest/libhidl-gen-utils_test/libhidl-gen-utils_test &&
-$ANDROID_BUILD_TOP/out/host/linux-x86/nativetest64/libhidl-gen-utils_test/libhidl-gen-utils_test &&
-echo SUCCESS
+    local COMPILE_TIME_TESTS=(\
+        hidl_error_test \
+        hidl_hash_test \
+        hidl_impl_test)
+
+    local RUN_TIME_TESTS=(\
+        libhidl-gen-utils_test \
+        hidl-gen-host_test \
+    )
+
+    $ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode -j \
+        ${COMPILE_TIME_TESTS[*]} ${RUN_TIME_TESTS[*]} || return
+
+    local BITNESS=("nativetest" "nativetest64")
+
+    for bits in ${BITNESS[@]}; do
+        for test in ${RUN_TIME_TESTS[@]}; do
+            echo $bits $test
+            $ANDROID_BUILD_TOP/out/host/linux-x86/$bits/$test/$test ||
+                FAILED_TESTS+=("$bits:$test")
+        done
+    done
+
+    echo
+    echo ===== SUMMARY =====
+    echo
+    if [ ${#FAILED_TESTS[@]} -gt 0 ]; then
+        for failed in ${FAILED_TESTS[@]}; do
+            echo "FAILED TEST: $failed"
+        done
+    else
+        echo "SUCCESS"
+    fi
+}
+
+run
\ No newline at end of file