Add check for hidl package root hash.

When compiling a module, say foo.bar.baz@1.0::IBaz, assume the package
root is foo.bar:some/dir/interfaces, then:
- look at the file some/dir/interfaces/current.txt
- read hash from file corresponding from foo.bar.baz@1.0::IBaz
- file supports same-line comments with '#'
- format of file is each line is blank or looks like:
    "<sha-256 hash> <fqName>"
- if the file is misformed or the hal does not match a sha in that file,
    then it is considered build breakage.

Test: build with and without changing frozen files
Bug: 34178341
Change-Id: Ieddbc796ea974ac7c2e8b95ca69009c31e0cfb60
diff --git a/Coordinator.cpp b/Coordinator.cpp
index 72c8557..dee56aa 100644
--- a/Coordinator.cpp
+++ b/Coordinator.cpp
@@ -26,6 +26,7 @@
 #include <hidl-util/StringHelper.h>
 
 #include "AST.h"
+#include "Hash.h"
 #include "Interface.h"
 
 extern android::status_t parseFile(android::AST *ast);
@@ -378,7 +379,14 @@
     }
 
     // enforce all rules.
-    status_t err = enforceMinorVersionUprevs(package);
+    status_t err;
+
+    err = enforceMinorVersionUprevs(package);
+    if (err != OK) {
+        return err;
+    }
+
+    err = enforceHashes(package);
     if (err != OK) {
         return err;
     }
@@ -491,6 +499,51 @@
     return OK;
 }
 
+status_t Coordinator::enforceHashes(const FQName &currentPackage) {
+    status_t err = OK;
+    std::vector<FQName> packageInterfaces;
+    err = appendPackageInterfacesToVector(currentPackage, &packageInterfaces);
+    if (err != OK) {
+        return err;
+    }
+
+    for (const FQName &currentFQName : packageInterfaces) {
+        AST *ast = parse(currentFQName);
+
+        if (ast == nullptr) {
+            err = UNKNOWN_ERROR;
+            continue;
+        }
+
+        std::string packageRootPath = getPackageRootPath(currentFQName);
+        std::string error;
+        std::vector<std::string> frozen = Hash::lookupHash(packageRootPath, currentFQName.string(), &error);
+
+        if (error.size() > 0) {
+            LOG(ERROR) << error;
+            err = UNKNOWN_ERROR;
+            continue;
+        }
+
+        // hash not define, interface not frozen
+        if (frozen.size() == 0) {
+            continue;
+        }
+
+        std::string currentHash = Hash::getHash(ast->getFilename()).hexString();
+
+        if(std::find(frozen.begin(), frozen.end(), currentHash) == frozen.end()) {
+            LOG(ERROR) << currentFQName.string() << " has hash " << currentHash
+                       << " which does not match hash on record. This interface has "
+                       << "been frozen. Do not change it!";
+            err = UNKNOWN_ERROR;
+            continue;
+        }
+    }
+
+    return err;
+}
+
 // static
 bool Coordinator::MakeParentHierarchy(const std::string &path) {
     static const mode_t kMode = 0755;