Merge "Export the license metadata files for dexpreopted bootjars to Make"
diff --git a/android/paths.go b/android/paths.go
index 05caebd..e7829b9 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -1474,14 +1474,11 @@
func PathForVndkRefAbiDump(ctx ModuleInstallPathContext, version, fileName string,
isNdk, isLlndkOrVndk, isGzip bool) OptionalPath {
- arches := ctx.DeviceConfig().Arches()
- if len(arches) == 0 {
- panic("device build with no primary arch")
- }
- currentArch := ctx.Arch()
- archNameAndVariant := currentArch.ArchType.String()
- if currentArch.ArchVariant != "" {
- archNameAndVariant += "_" + currentArch.ArchVariant
+ currentArchType := ctx.Arch().ArchType
+ primaryArchType := ctx.Config().DevicePrimaryArchType()
+ archName := currentArchType.String()
+ if currentArchType != primaryArchType {
+ archName += "_" + primaryArchType.String()
}
var dirName string
@@ -1503,7 +1500,7 @@
}
return ExistentPathForSource(ctx, "prebuilts", "abi-dumps", dirName,
- version, binderBitness, archNameAndVariant, "source-based",
+ version, binderBitness, archName, "source-based",
fileName+ext)
}
diff --git a/java/legacy_core_platform_api_usage.go b/java/legacy_core_platform_api_usage.go
index e3396c1..8e22491 100644
--- a/java/legacy_core_platform_api_usage.go
+++ b/java/legacy_core_platform_api_usage.go
@@ -81,7 +81,6 @@
"ds-car-docs", // for AAOS API documentation only
"DynamicSystemInstallationService",
"EmergencyInfo-lib",
- "ethernet-service",
"EthernetServiceTests",
"ExternalStorageProvider",
"face-V1-0-javalib",
diff --git a/mk2rbc/mk2rbc.go b/mk2rbc/mk2rbc.go
index d8b88b2..35d7d4d 100644
--- a/mk2rbc/mk2rbc.go
+++ b/mk2rbc/mk2rbc.go
@@ -407,6 +407,8 @@
dependentModules map[string]*moduleInfo
soongNamespaces map[string]map[string]bool
includeTops []string
+ typeHints map[string]starlarkType
+ atTopOfMakefile bool
}
func newParseContext(ss *StarlarkScript, nodes []mkparser.Node) *parseContext {
@@ -450,6 +452,8 @@
dependentModules: make(map[string]*moduleInfo),
soongNamespaces: make(map[string]map[string]bool),
includeTops: []string{},
+ typeHints: make(map[string]starlarkType),
+ atTopOfMakefile: true,
}
ctx.pushVarAssignments()
for _, item := range predefined {
@@ -1680,7 +1684,8 @@
// Clear the includeTops after each non-comment statement
// so that include annotations placed on certain statements don't apply
// globally for the rest of the makefile was well.
- if _, wasComment := node.(*mkparser.Comment); !wasComment && len(ctx.includeTops) > 0 {
+ if _, wasComment := node.(*mkparser.Comment); !wasComment {
+ ctx.atTopOfMakefile = false
ctx.includeTops = []string{}
}
@@ -1690,6 +1695,12 @@
return result
}
+// The types allowed in a type_hint
+var typeHintMap = map[string]starlarkType{
+ "string": starlarkTypeString,
+ "list": starlarkTypeList,
+}
+
// Processes annotation. An annotation is a comment that starts with #RBC# and provides
// a conversion hint -- say, where to look for the dynamically calculated inherit/include
// paths. Returns true if the comment was a successfully-handled annotation.
@@ -1714,6 +1725,35 @@
}
ctx.includeTops = append(ctx.includeTops, p)
return nil, true
+ } else if p, ok := maybeTrim(annotation, "type_hint"); ok {
+ // Type hints must come at the beginning the file, to avoid confusion
+ // if a type hint was specified later and thus only takes effect for half
+ // of the file.
+ if !ctx.atTopOfMakefile {
+ return ctx.newBadNode(cnode, "type_hint annotations must come before the first Makefile statement"), true
+ }
+
+ parts := strings.Fields(p)
+ if len(parts) <= 1 {
+ return ctx.newBadNode(cnode, "Invalid type_hint annotation: %s. Must be a variable type followed by a list of variables of that type", p), true
+ }
+
+ var varType starlarkType
+ if varType, ok = typeHintMap[parts[0]]; !ok {
+ varType = starlarkTypeUnknown
+ }
+ if varType == starlarkTypeUnknown {
+ return ctx.newBadNode(cnode, "Invalid type_hint annotation. Only list/string types are accepted, found %s", parts[0]), true
+ }
+
+ for _, name := range parts[1:] {
+ // Don't allow duplicate type hints
+ if _, ok := ctx.typeHints[name]; ok {
+ return ctx.newBadNode(cnode, "Duplicate type hint for variable %s", name), true
+ }
+ ctx.typeHints[name] = varType
+ }
+ return nil, true
}
return ctx.newBadNode(cnode, "unsupported annotation %s", cnode.Comment), true
}
diff --git a/mk2rbc/mk2rbc_test.go b/mk2rbc/mk2rbc_test.go
index 35c54d2..4084660 100644
--- a/mk2rbc/mk2rbc_test.go
+++ b/mk2rbc/mk2rbc_test.go
@@ -1406,6 +1406,53 @@
pass
`,
},
+ {
+ desc: "Type hints",
+ mkname: "product.mk",
+ in: `
+# Test type hints
+#RBC# type_hint list MY_VAR MY_VAR_2
+# Unsupported type
+#RBC# type_hint bool MY_VAR_3
+# Invalid syntax
+#RBC# type_hint list
+# Duplicated variable
+#RBC# type_hint list MY_VAR_2
+#RBC# type_hint list my-local-var-with-dashes
+
+MY_VAR := foo
+MY_VAR_UNHINTED := foo
+
+# Vars set after other statements still get the hint
+MY_VAR_2 := foo
+
+# You can't specify a type hint after the first statement
+#RBC# type_hint list MY_VAR_4
+MY_VAR_4 := foo
+
+my-local-var-with-dashes := foo
+`,
+ expected: `# Test type hints
+# Unsupported type
+load("//build/make/core:product_config.rbc", "rblf")
+
+def init(g, handle):
+ cfg = rblf.cfg(handle)
+ rblf.mk2rbc_error("product.mk:5", "Invalid type_hint annotation. Only list/string types are accepted, found bool")
+ # Invalid syntax
+ rblf.mk2rbc_error("product.mk:7", "Invalid type_hint annotation: list. Must be a variable type followed by a list of variables of that type")
+ # Duplicated variable
+ rblf.mk2rbc_error("product.mk:9", "Duplicate type hint for variable MY_VAR_2")
+ g["MY_VAR"] = ["foo"]
+ g["MY_VAR_UNHINTED"] = "foo"
+ # Vars set after other statements still get the hint
+ g["MY_VAR_2"] = ["foo"]
+ # You can't specify a type hint after the first statement
+ rblf.mk2rbc_error("product.mk:19", "type_hint annotations must come before the first Makefile statement")
+ g["MY_VAR_4"] = "foo"
+ _my_local_var_with_dashes = ["foo"]
+`,
+ },
}
var known_variables = []struct {
diff --git a/mk2rbc/variable.go b/mk2rbc/variable.go
index 3241a38..506266a 100644
--- a/mk2rbc/variable.go
+++ b/mk2rbc/variable.go
@@ -291,6 +291,12 @@
// addVariable returns a variable with a given name. A variable is
// added if it does not exist yet.
func (ctx *parseContext) addVariable(name string) variable {
+ // Get the hintType before potentially changing the variable name
+ var hintType starlarkType
+ var ok bool
+ if hintType, ok = ctx.typeHints[name]; !ok {
+ hintType = starlarkTypeUnknown
+ }
// Heuristics: if variable's name is all lowercase, consider it local
// string variable.
isLocalVariable := name == strings.ToLower(name)
@@ -301,8 +307,8 @@
}
v, found := ctx.variables[name]
if !found {
- _, preset := presetVariables[name]
if vi, found := KnownVariables[name]; found {
+ _, preset := presetVariables[name]
switch vi.class {
case VarClassConfig:
v = &productConfigVariable{baseVariable{nam: name, typ: vi.valueType, preset: preset}}
@@ -310,10 +316,10 @@
v = &otherGlobalVariable{baseVariable{nam: name, typ: vi.valueType, preset: preset}}
}
} else if isLocalVariable {
- v = &localVariable{baseVariable{nam: name, typ: starlarkTypeUnknown}}
+ v = &localVariable{baseVariable{nam: name, typ: hintType}}
} else {
- vt := starlarkTypeUnknown
- if strings.HasPrefix(name, "LOCAL_") {
+ vt := hintType
+ if strings.HasPrefix(name, "LOCAL_") && vt == starlarkTypeUnknown {
// Heuristics: local variables that contribute to corresponding config variables
if cfgVarName, found := localProductConfigVariables[name]; found {
vi, found2 := KnownVariables[cfgVarName]
diff --git a/scripts/hiddenapi/signature_trie.py b/scripts/hiddenapi/signature_trie.py
index 2ea8c49..e813a97 100644
--- a/scripts/hiddenapi/signature_trie.py
+++ b/scripts/hiddenapi/signature_trie.py
@@ -22,6 +22,19 @@
@dataclasses.dataclass()
class Node:
+ """A node in the signature trie."""
+
+ # The type of the node.
+ #
+ # Leaf nodes are of type "member".
+ # Interior nodes can be either "package", or "class".
+ type: str
+
+ # The selector of the node.
+ #
+ # That is a string that can be used to select the node, e.g. in a pattern
+ # that is passed to InteriorNode.get_matching_rows().
+ selector: str
def values(self, selector):
"""Get the values from a set of selected nodes.
@@ -48,6 +61,10 @@
"""
raise NotImplementedError("Please Implement this method")
+ def child_nodes(self):
+ """Get an iterable of the child nodes of this node."""
+ raise NotImplementedError("Please Implement this method")
+
# pylint: disable=line-too-long
@dataclasses.dataclass()
@@ -110,74 +127,149 @@
# 0 - java/lang/Character$UnicodeScript
# 1 - of(I)Ljava/lang/Character$UnicodeScript;
parts = text.split(";->")
+ # If there is no member then this will be an empty list.
member = parts[1:]
# Split the qualified class name into packages, and class name.
# 0 - java
# 1 - lang
# 2 - Character$UnicodeScript
elements = parts[0].split("/")
- packages = elements[0:-1]
- class_name = elements[-1]
- if class_name in ("*", "**"): # pylint: disable=no-else-return
+ last_element = elements[-1]
+ wildcard = []
+ classes = []
+ if "*" in last_element:
+ if last_element not in ("*", "**"):
+ raise Exception(f"Invalid signature '{signature}': invalid "
+ f"wildcard '{last_element}'")
+ packages = elements[0:-1]
# Cannot specify a wildcard and target a specific member
- if len(member) != 0:
- raise Exception(f"Invalid signature {signature}: contains "
- f"wildcard {class_name} and "
- f"member signature {member[0]}")
- wildcard = [class_name]
- # Assemble the parts into a single list, adding prefixes to identify
- # the different parts.
- # 0 - package:java
- # 1 - package:lang
- # 2 - *
- return list(chain(["package:" + x for x in packages], wildcard))
+ if member:
+ raise Exception(f"Invalid signature '{signature}': contains "
+ f"wildcard '{last_element}' and "
+ f"member signature '{member[0]}'")
+ wildcard = [last_element]
+ elif last_element.islower():
+ raise Exception(f"Invalid signature '{signature}': last element "
+ f"'{last_element}' is lower case but should be an "
+ f"upper case class name or wildcard")
else:
+ packages = elements[0:-1]
# Split the class name into outer / inner classes
# 0 - Character
# 1 - UnicodeScript
- classes = class_name.split("$")
- # Assemble the parts into a single list, adding prefixes to identify
- # the different parts.
- # 0 - package:java
- # 1 - package:lang
- # 2 - class:Character
- # 3 - class:UnicodeScript
- # 4 - member:of(I)Ljava/lang/Character$UnicodeScript;
- return list(
- chain(["package:" + x for x in packages],
- ["class:" + x for x in classes],
- ["member:" + x for x in member]))
+ classes = last_element.removesuffix(";").split("$")
+
+ # Assemble the parts into a single list, adding prefixes to identify
+ # the different parts. If a wildcard is provided then it looks something
+ # like this:
+ # 0 - package:java
+ # 1 - package:lang
+ # 2 - *
+ #
+ # Otherwise, it looks something like this:
+ # 0 - package:java
+ # 1 - package:lang
+ # 2 - class:Character
+ # 3 - class:UnicodeScript
+ # 4 - member:of(I)Ljava/lang/Character$UnicodeScript;
+ return list(
+ chain([("package", x) for x in packages],
+ [("class", x) for x in classes],
+ [("member", x) for x in member],
+ [("wildcard", x) for x in wildcard]))
# pylint: enable=line-too-long
- def add(self, signature, value):
+ @staticmethod
+ def split_element(element):
+ element_type, element_value = element
+ return element_type, element_value
+
+ @staticmethod
+ def element_type(element):
+ element_type, _ = InteriorNode.split_element(element)
+ return element_type
+
+ @staticmethod
+ def elements_to_selector(elements):
+ """Compute a selector for a set of elements.
+
+ A selector uniquely identifies a specific Node in the trie. It is
+ essentially a prefix of a signature (without the leading L).
+
+ e.g. a trie containing "Ljava/lang/Object;->String()Ljava/lang/String;"
+ would contain nodes with the following selectors:
+ * "java"
+ * "java/lang"
+ * "java/lang/Object"
+ * "java/lang/Object;->String()Ljava/lang/String;"
+ """
+ signature = ""
+ preceding_type = ""
+ for element in elements:
+ element_type, element_value = InteriorNode.split_element(element)
+ separator = ""
+ if element_type == "package":
+ separator = "/"
+ elif element_type == "class":
+ if preceding_type == "class":
+ separator = "$"
+ else:
+ separator = "/"
+ elif element_type == "wildcard":
+ separator = "/"
+ elif element_type == "member":
+ separator += ";->"
+
+ if signature:
+ signature += separator
+
+ signature += element_value
+
+ preceding_type = element_type
+
+ return signature
+
+ def add(self, signature, value, only_if_matches=False):
"""Associate the value with the specific signature.
:param signature: the member signature
:param value: the value to associated with the signature
+ :param only_if_matches: True if the value is added only if the signature
+ matches at least one of the existing top level packages.
:return: n/a
"""
# Split the signature into elements.
elements = self.signature_to_elements(signature)
# Find the Node associated with the deepest class.
node = self
- for element in elements[:-1]:
+ for index, element in enumerate(elements[:-1]):
if element in node.nodes:
node = node.nodes[element]
+ elif only_if_matches and index == 0:
+ return
else:
- next_node = InteriorNode()
+ selector = self.elements_to_selector(elements[0:index + 1])
+ next_node = InteriorNode(
+ type=InteriorNode.element_type(element), selector=selector)
node.nodes[element] = next_node
node = next_node
# Add a Leaf containing the value and associate it with the member
# signature within the class.
last_element = elements[-1]
- if not last_element.startswith("member:"):
+ last_element_type = self.element_type(last_element)
+ if last_element_type != "member":
raise Exception(
f"Invalid signature: {signature}, does not identify a "
"specific member")
if last_element in node.nodes:
raise Exception(f"Duplicate signature: {signature}")
- node.nodes[last_element] = Leaf(value)
+ leaf = Leaf(
+ type=last_element_type,
+ selector=signature,
+ value=value,
+ )
+ node.nodes[last_element] = leaf
def get_matching_rows(self, pattern):
"""Get the values (plural) associated with the pattern.
@@ -188,10 +280,6 @@
If the pattern is a class then this will return a list containing the
values associated with all members of that class.
- If the pattern is a package then this will return a list containing the
- values associated with all the members of all the classes in that
- package and sub-packages.
-
If the pattern ends with "*" then the preceding part is treated as a
package and this will return a list containing the values associated
with all the members of all the classes in that package.
@@ -213,11 +301,12 @@
selector = lambda x: True
last_element = elements[-1]
- if last_element in ("*", "**"):
+ last_element_type, last_element_value = self.split_element(last_element)
+ if last_element_type == "wildcard":
elements = elements[:-1]
- if last_element == "*":
+ if last_element_value == "*":
# Do not include values from sub-packages.
- selector = lambda x: not x.startswith("package:")
+ selector = lambda x: InteriorNode.element_type(x) != "package"
for element in elements:
if element in node.nodes:
@@ -236,6 +325,8 @@
if selector(key):
node.append_values(values, lambda x: True)
+ def child_nodes(self):
+ return self.nodes.values()
@dataclasses.dataclass()
@@ -251,6 +342,9 @@
def append_values(self, values, selector):
values.append([self.value])
+ def child_nodes(self):
+ return []
+
def signature_trie():
- return InteriorNode()
+ return InteriorNode(type="root", selector="")
diff --git a/scripts/hiddenapi/signature_trie_test.py b/scripts/hiddenapi/signature_trie_test.py
index 2dc79d0..1295691 100755
--- a/scripts/hiddenapi/signature_trie_test.py
+++ b/scripts/hiddenapi/signature_trie_test.py
@@ -27,99 +27,127 @@
def signature_to_elements(signature):
return InteriorNode.signature_to_elements(signature)
+ @staticmethod
+ def elements_to_signature(elements):
+ return InteriorNode.elements_to_selector(elements)
+
def test_nested_inner_classes(self):
elements = [
- "package:java",
- "package:lang",
- "class:ProcessBuilder",
- "class:Redirect",
- "class:1",
- "member:<init>()V",
+ ("package", "java"),
+ ("package", "lang"),
+ ("class", "ProcessBuilder"),
+ ("class", "Redirect"),
+ ("class", "1"),
+ ("member", "<init>()V"),
]
signature = "Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V"
self.assertEqual(elements, self.signature_to_elements(signature))
+ self.assertEqual(signature, "L" + self.elements_to_signature(elements))
def test_basic_member(self):
elements = [
- "package:java",
- "package:lang",
- "class:Object",
- "member:hashCode()I",
+ ("package", "java"),
+ ("package", "lang"),
+ ("class", "Object"),
+ ("member", "hashCode()I"),
]
signature = "Ljava/lang/Object;->hashCode()I"
self.assertEqual(elements, self.signature_to_elements(signature))
+ self.assertEqual(signature, "L" + self.elements_to_signature(elements))
def test_double_dollar_class(self):
elements = [
- "package:java",
- "package:lang",
- "class:CharSequence",
- "class:",
- "class:ExternalSyntheticLambda0",
- "member:<init>(Ljava/lang/CharSequence;)V",
+ ("package", "java"),
+ ("package", "lang"),
+ ("class", "CharSequence"),
+ ("class", ""),
+ ("class", "ExternalSyntheticLambda0"),
+ ("member", "<init>(Ljava/lang/CharSequence;)V"),
]
signature = "Ljava/lang/CharSequence$$ExternalSyntheticLambda0;" \
"-><init>(Ljava/lang/CharSequence;)V"
self.assertEqual(elements, self.signature_to_elements(signature))
+ self.assertEqual(signature, "L" + self.elements_to_signature(elements))
def test_no_member(self):
elements = [
- "package:java",
- "package:lang",
- "class:CharSequence",
- "class:",
- "class:ExternalSyntheticLambda0",
+ ("package", "java"),
+ ("package", "lang"),
+ ("class", "CharSequence"),
+ ("class", ""),
+ ("class", "ExternalSyntheticLambda0"),
]
signature = "Ljava/lang/CharSequence$$ExternalSyntheticLambda0"
self.assertEqual(elements, self.signature_to_elements(signature))
+ self.assertEqual(signature, "L" + self.elements_to_signature(elements))
def test_wildcard(self):
elements = [
- "package:java",
- "package:lang",
- "*",
+ ("package", "java"),
+ ("package", "lang"),
+ ("wildcard", "*"),
]
signature = "java/lang/*"
self.assertEqual(elements, self.signature_to_elements(signature))
+ self.assertEqual(signature, self.elements_to_signature(elements))
def test_recursive_wildcard(self):
elements = [
- "package:java",
- "package:lang",
- "**",
+ ("package", "java"),
+ ("package", "lang"),
+ ("wildcard", "**"),
]
signature = "java/lang/**"
self.assertEqual(elements, self.signature_to_elements(signature))
+ self.assertEqual(signature, self.elements_to_signature(elements))
def test_no_packages_wildcard(self):
elements = [
- "*",
+ ("wildcard", "*"),
]
signature = "*"
self.assertEqual(elements, self.signature_to_elements(signature))
+ self.assertEqual(signature, self.elements_to_signature(elements))
def test_no_packages_recursive_wildcard(self):
elements = [
- "**",
+ ("wildcard", "**"),
]
signature = "**"
self.assertEqual(elements, self.signature_to_elements(signature))
+ self.assertEqual(signature, self.elements_to_signature(elements))
+
+ def test_invalid_no_class_or_wildcard(self):
+ signature = "java/lang"
+ with self.assertRaises(Exception) as context:
+ self.signature_to_elements(signature)
+ self.assertIn(
+ "last element 'lang' is lower case but should be an "
+ "upper case class name or wildcard", str(context.exception))
def test_non_standard_class_name(self):
elements = [
- "package:javax",
- "package:crypto",
- "class:extObjectInputStream",
+ ("package", "javax"),
+ ("package", "crypto"),
+ ("class", "extObjectInputStream"),
]
signature = "Ljavax/crypto/extObjectInputStream"
self.assertEqual(elements, self.signature_to_elements(signature))
+ self.assertEqual(signature, "L" + self.elements_to_signature(elements))
+
+ def test_invalid_pattern_wildcard(self):
+ pattern = "Ljava/lang/Class*"
+ with self.assertRaises(Exception) as context:
+ self.signature_to_elements(pattern)
+ self.assertIn("invalid wildcard 'Class*'", str(context.exception))
def test_invalid_pattern_wildcard_and_member(self):
pattern = "Ljava/lang/*;->hashCode()I"
with self.assertRaises(Exception) as context:
self.signature_to_elements(pattern)
- self.assertIn("contains wildcard * and member signature hashCode()I",
- str(context.exception))
+ self.assertIn(
+ "contains wildcard '*' and member signature 'hashCode()I'",
+ str(context.exception))
class TestGetMatchingRows(unittest.TestCase):
@@ -185,6 +213,18 @@
"Ljava/util/zip/ZipFile;-><clinit>()V",
])
+ def test_node_wildcard(self):
+ trie = self.read_trie()
+ node = list(trie.child_nodes())[0]
+ self.check_node_patterns(node, "**", [
+ "Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;",
+ "Ljava/lang/Character;->serialVersionUID:J",
+ "Ljava/lang/Object;->hashCode()I",
+ "Ljava/lang/Object;->toString()Ljava/lang/String;",
+ "Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V",
+ "Ljava/util/zip/ZipFile;-><clinit>()V",
+ ])
+
# pylint: enable=line-too-long