Sync internal master and AOSP sepolicy.

Bug: 37916906
Test: Builds 'n' boots.
Change-Id: Ia1d86264446ebecc1ca79f32f11354921bc77668
Merged-In: I208ec6a864127a059fb389417a9c6b259d7474cb
diff --git a/tests/mini_parser.py b/tests/mini_parser.py
new file mode 100644
index 0000000..fbeaff8
--- /dev/null
+++ b/tests/mini_parser.py
@@ -0,0 +1,100 @@
+from os.path import basename
+import re
+import sys
+
+# A very limited parser whose job is to process the compatibility mapping
+# files and retrieve type and attribute information until proper support is
+# built into libsepol
+
+# get the text in the next matching parens
+
+class MiniCilParser:
+    types = set() # types declared in mapping
+    pubtypes = set()
+    typeattributes = set() # attributes declared in mapping
+    typeattributesets = {} # sets defined in mapping
+    rTypeattributesets = {} # reverse mapping of above sets
+    apiLevel = None
+
+    def _getNextStmt(self, infile):
+        parens = 0
+        s = ""
+        c = infile.read(1)
+        # get to first statement
+        while c and c != "(":
+            c = infile.read(1)
+
+        parens += 1
+        c = infile.read(1)
+        while c and parens != 0:
+            s += c
+            c = infile.read(1)
+            if c == ';':
+                # comment, get rid of rest of the line
+                while c != '\n':
+                    c = infile.read(1)
+            elif c == '(':
+                parens += 1
+            elif c == ')':
+                parens -= 1
+        return s
+
+    def _parseType(self, stmt):
+        m = re.match(r"type\s+(.+)", stmt)
+        self.types.add(m.group(1))
+        return
+
+    def _parseTypeattribute(self, stmt):
+        m = re.match(r"typeattribute\s+(.+)", stmt)
+        self.typeattributes.add(m.group(1))
+        return
+
+    def _parseTypeattributeset(self, stmt):
+        m = re.match(r"typeattributeset\s+(.+?)\s+\((.+?)\)", stmt, flags = re.M |re.S)
+        ta = m.group(1)
+        # this isn't proper expression parsing, but will do for our
+        # current use
+        tas = m.group(2).split()
+
+        if self.typeattributesets.get(ta) is None:
+            self.typeattributesets[ta] = set()
+        self.typeattributesets[ta].update(set(tas))
+        for t in tas:
+            if self.rTypeattributesets.get(t) is None:
+                self.rTypeattributesets[t] = set()
+            self.rTypeattributesets[t].update(set(ta))
+
+        # check to see if this typeattributeset is a versioned public type
+        pub = re.match(r"(\w+)_\d+_\d+", ta)
+        if pub is not None:
+            self.pubtypes.add(pub.group(1))
+        return
+
+    def _parseStmt(self, stmt):
+        if re.match(r"type\s+.+", stmt):
+            self._parseType(stmt)
+        elif re.match(r"typeattribute\s+.+", stmt):
+            self._parseTypeattribute(stmt)
+        elif re.match(r"typeattributeset\s+.+", stmt):
+            self._parseTypeattributeset(stmt)
+        else:
+            m = re.match(r"(\w+)\s+.+", stmt)
+            ret = "Warning: Unknown statement type (" + m.group(1) + ") in "
+            ret += "mapping file, perhaps consider adding support for it in "
+            ret += "system/sepolicy/tests/mini_parser.py!\n"
+            print ret
+        return
+
+    def __init__(self, policyFile):
+        with open(policyFile, 'r') as infile:
+            s = self._getNextStmt(infile)
+            while s:
+                self._parseStmt(s)
+                s = self._getNextStmt(infile)
+        fn = basename(policyFile)
+        m = re.match(r"(\d+\.\d+).+\.cil", fn)
+        self.apiLevel = m.group(1)
+
+if __name__ == '__main__':
+    f = sys.argv[1]
+    p = MiniCilParser(f)