aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--androidmk/cmd/androidmk/android.go52
-rw-r--r--androidmk/cmd/androidmk/androidmk_test.go204
-rw-r--r--bpfix/bpfix/bpfix.go154
-rw-r--r--bpfix/bpfix/bpfix_test.go59
4 files changed, 468 insertions, 1 deletions
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index e7f2531d..aef8944d 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -56,6 +56,7 @@ var rewriteProperties = map[string](func(variableAssignmentContext) error){
"LOCAL_CFLAGS": cflags,
"LOCAL_UNINSTALLABLE_MODULE": invert("installable"),
"LOCAL_PROGUARD_ENABLED": proguardEnabled,
+ "LOCAL_MODULE_PATH": prebuiltModulePath,
// composite functions
"LOCAL_MODULE_TAGS": includeVariableIf(bpVariable{"tags", bpparser.ListType}, not(valueDumpEquals("optional"))),
@@ -519,6 +520,55 @@ func prebuiltClass(ctx variableAssignmentContext) error {
return nil
}
+func makeBlueprintStringAssignment(file *bpFile, prefix string, suffix string, value string) error {
+ val, err := makeVariableToBlueprint(file, mkparser.SimpleMakeString(value, mkparser.NoPos), bpparser.StringType)
+ if err == nil {
+ err = setVariable(file, false, prefix, suffix, val, true)
+ }
+ return err
+}
+
+// If variable is a literal variable name, return the name, otherwise return ""
+func varLiteralName(variable mkparser.Variable) string {
+ if len(variable.Name.Variables) == 0 {
+ return variable.Name.Strings[0]
+ }
+ return ""
+}
+
+func prebuiltModulePath(ctx variableAssignmentContext) error {
+ // Cannot handle appending
+ if ctx.append {
+ return fmt.Errorf("Cannot handle appending to LOCAL_MODULE_PATH")
+ }
+ // Analyze value in order to set the correct values for the 'device_specific',
+ // 'product_specific', 'product_services_specific' 'vendor'/'soc_specific',
+ // 'product_services_specific' attribute. Two cases are allowed:
+ // $(VAR)/<literal-value>
+ // $(PRODUCT_OUT)/$(TARGET_COPY_OUT_VENDOR)/<literal-value>
+ // The last case is equivalent to $(TARGET_OUT_VENDOR)/<literal-value>
+ // Map the variable name if present to `local_module_path_var`
+ // Map literal-path to local_module_path_fixed
+ varname := ""
+ fixed := ""
+ val := ctx.mkvalue
+ if len(val.Variables) == 1 && varLiteralName(val.Variables[0]) != "" && len(val.Strings) == 2 && val.Strings[0] == "" {
+ fixed = val.Strings[1]
+ varname = val.Variables[0].Name.Strings[0]
+ } else if len(val.Variables) == 2 && varLiteralName(val.Variables[0]) == "PRODUCT_OUT" && varLiteralName(val.Variables[1]) == "TARGET_COPY_OUT_VENDOR" &&
+ len(val.Strings) == 3 && val.Strings[0] == "" && val.Strings[1] == "/" {
+ fixed = val.Strings[2]
+ varname = "TARGET_OUT_VENDOR"
+ } else {
+ return fmt.Errorf("LOCAL_MODULE_PATH value should start with $(<some-varaible>)/ or $(PRODUCT_OUT)/$(TARGET_COPY_VENDOR)/")
+ }
+ err := makeBlueprintStringAssignment(ctx.file, "local_module_path", "var", varname)
+ if err == nil && fixed != "" {
+ err = makeBlueprintStringAssignment(ctx.file, "local_module_path", "fixed", fixed)
+ }
+ return err
+}
+
func ldflags(ctx variableAssignmentContext) error {
val, err := makeVariableToBlueprint(ctx.file, ctx.mkvalue, bpparser.ListType)
if err != nil {
@@ -816,6 +866,7 @@ var prebuiltTypes = map[string]string{
"STATIC_LIBRARIES": "cc_prebuilt_library_static",
"EXECUTABLES": "cc_prebuilt_binary",
"JAVA_LIBRARIES": "java_import",
+ "ETC": "prebuilt_etc",
}
var soongModuleTypes = map[string]bool{}
@@ -834,7 +885,6 @@ func androidScope() mkparser.Scope {
globalScope.SetFunc("first-makefiles-under", includeIgnored)
globalScope.SetFunc("all-named-subdir-makefiles", includeIgnored)
globalScope.SetFunc("all-subdir-makefiles", includeIgnored)
-
for k, v := range moduleTypes {
globalScope.Set(k, v)
soongModuleTypes[v] = true
diff --git a/androidmk/cmd/androidmk/androidmk_test.go b/androidmk/cmd/androidmk/androidmk_test.go
index 5fbe62a0..52b8476a 100644
--- a/androidmk/cmd/androidmk/androidmk_test.go
+++ b/androidmk/cmd/androidmk/androidmk_test.go
@@ -824,6 +824,210 @@ java_library {
}
`,
},
+ {
+ desc: "prebuilt_etc_TARGET_OUT_ETC",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := etc.test1
+LOCAL_SRC_FILES := mymod
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/foo/bar
+include $(BUILD_PREBUILT)
+`,
+ expected: `
+prebuilt_etc {
+ name: "etc.test1",
+ src: "mymod",
+ sub_dir: "foo/bar",
+
+}
+`,
+ },
+
+ {
+ desc: "prebuilt_etc_PRODUCT_OUT/system/etc",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := etc.test1
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(PRODUCT_OUT)/system/etc/foo/bar
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+include $(BUILD_PREBUILT)
+`,
+ expected: `
+prebuilt_etc {
+ name: "etc.test1",
+
+ src: "etc.test1",
+ sub_dir: "foo/bar",
+
+}
+`,
+ },
+ {
+ desc: "prebuilt_etc_TARGET_OUT_ODM/etc",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := etc.test1
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_ODM)/etc/foo/bar
+include $(BUILD_PREBUILT)
+`,
+ expected: `
+prebuilt_etc {
+ name: "etc.test1",
+ sub_dir: "foo/bar",
+ device_specific: true,
+
+}
+`,
+ },
+ {
+ desc: "prebuilt_etc_TARGET_OUT_PRODUCT/etc",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := etc.test1
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT)/etc/foo/bar
+include $(BUILD_PREBUILT)
+`,
+ expected: `
+prebuilt_etc {
+ name: "etc.test1",
+ sub_dir: "foo/bar",
+ product_specific: true,
+
+
+}
+`,
+ },
+ {
+ desc: "prebuilt_etc_TARGET_OUT_PRODUCT_ETC",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := etc.test1
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT_ETC)/foo/bar
+include $(BUILD_PREBUILT)
+`,
+ expected: `
+prebuilt_etc {
+ name: "etc.test1",
+ sub_dir: "foo/bar",
+ product_specific: true,
+
+}
+`,
+ },
+ {
+ desc: "prebuilt_etc_TARGET_OUT_PRODUCT_SERVICES/etc",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := etc.test1
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT_SERVICES)/etc/foo/bar
+include $(BUILD_PREBUILT)
+`,
+ expected: `
+prebuilt_etc {
+ name: "etc.test1",
+ sub_dir: "foo/bar",
+ product_services_specific: true,
+
+}
+`,
+ },
+ {
+ desc: "prebuilt_etc_TARGET_OUT_PRODUCT_SERVICES_ETC",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := etc.test1
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT_SERVICES_ETC)/foo/bar
+include $(BUILD_PREBUILT)
+`,
+ expected: `
+prebuilt_etc {
+ name: "etc.test1",
+ sub_dir: "foo/bar",
+ product_services_specific: true,
+
+
+}
+`,
+ },
+ {
+ desc: "prebuilt_etc_TARGET_OUT_VENDOR/etc",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := etc.test1
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/etc/foo/bar
+include $(BUILD_PREBUILT)
+`,
+ expected: `
+prebuilt_etc {
+ name: "etc.test1",
+ sub_dir: "foo/bar",
+ proprietary: true,
+
+}
+`,
+ },
+ {
+ desc: "prebuilt_etc_PRODUCT_OUT/TARGET_COPY_OUT_VENDOR/etc",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := etc.test1
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(PRODUCT_OUT)/$(TARGET_COPY_OUT_VENDOR)/etc/foo/bar
+include $(BUILD_PREBUILT)
+`,
+ expected: `
+prebuilt_etc {
+ name: "etc.test1",
+ sub_dir: "foo/bar",
+ proprietary: true,
+
+}
+`,
+ },
+ {
+ desc: "prebuilt_etc_TARGET_OUT_VENDOR_ETC",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := etc.test1
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_ETC)/foo/bar
+include $(BUILD_PREBUILT)
+`,
+ expected: `
+prebuilt_etc {
+ name: "etc.test1",
+ sub_dir: "foo/bar",
+ proprietary: true,
+
+}
+`,
+ },
+ {
+ desc: "prebuilt_etc_TARGET_RECOVERY_ROOT_OUT/system/etc",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := etc.test1
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/system/etc/foo/bar
+include $(BUILD_PREBUILT)
+`,
+ expected: `
+prebuilt_etc {
+ name: "etc.test1",
+ sub_dir: "foo/bar",
+ recovery: true,
+
+}
+`,
+ },
}
func TestEndToEnd(t *testing.T) {
diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go
index 6a755176..11f1877e 100644
--- a/bpfix/bpfix/bpfix.go
+++ b/bpfix/bpfix/bpfix.go
@@ -83,6 +83,10 @@ var fixSteps = []fixStep{
fix: rewriteJavaStaticLibs,
},
{
+ name: "rewritePrebuiltEtc",
+ fix: rewriteAndroidmkPrebuiltEtc,
+ },
+ {
name: "mergeMatchingModuleProperties",
fix: runPatchListMod(mergeMatchingModuleProperties),
},
@@ -407,6 +411,156 @@ func rewriteAndroidmkJavaLibs(f *Fixer) error {
return nil
}
+// Helper function to get the value of a string-valued property in a given compound property.
+func getStringProperty(prop *parser.Property, fieldName string) string {
+ if propsAsMap, ok := prop.Value.(*parser.Map); ok {
+ for _, propField := range propsAsMap.Properties {
+ if fieldName == propField.Name {
+ if propFieldAsString, ok := propField.Value.(*parser.String); ok {
+ return propFieldAsString.Value
+ } else {
+ return ""
+ }
+ }
+ }
+ }
+ return ""
+}
+
+// Create sub_dir: attribute for the given path
+func makePrebuiltEtcDestination(mod *parser.Module, path string) {
+ mod.Properties = append(mod.Properties, &parser.Property{
+ Name: "sub_dir",
+ Value: &parser.String{Value: path},
+ })
+}
+
+// Set the value of the given attribute to the error message
+func indicateAttributeError(mod *parser.Module, attributeName string, format string, a ...interface{}) error {
+ msg := fmt.Sprintf(format, a...)
+ mod.Properties = append(mod.Properties, &parser.Property{
+ Name: attributeName,
+ Value: &parser.String{Value: "ERROR: " + msg},
+ })
+ return errors.New(msg)
+}
+
+// If a variable is LOCAL_MODULE, get its value from the 'name' attribute.
+// This handles the statement
+// LOCAL_SRC_FILES := $(LOCAL_MODULE)
+// which occurs often.
+func resolveLocalModule(mod *parser.Module, val parser.Expression) parser.Expression {
+ if varLocalName, ok := val.(*parser.Variable); ok {
+ if varLocalName.Name == "LOCAL_MODULE" {
+ if v, ok := getLiteralStringProperty(mod, "name"); ok {
+ return v
+ }
+ }
+ }
+ return val
+}
+
+// A prefix to strip before setting 'filename' attribute and an array of boolean attributes to set.
+type filenamePrefixToFlags struct {
+ prefix string
+ flags []string
+}
+
+var localModulePathRewrite = map[string][]filenamePrefixToFlags{
+ "HOST_OUT": {{prefix: "/etc"}},
+ "PRODUCT_OUT": {{prefix: "/system/etc"}, {prefix: "/vendor/etc", flags: []string{"proprietary"}}},
+ "TARGET_OUT": {{prefix: "/etc"}},
+ "TARGET_OUT_ETC": {{prefix: ""}},
+ "TARGET_OUT_PRODUCT": {{prefix: "/etc", flags: []string{"product_specific"}}},
+ "TARGET_OUT_PRODUCT_ETC": {{prefix: "", flags: []string{"product_specific"}}},
+ "TARGET_OUT_ODM": {{prefix: "/etc", flags: []string{"device_specific"}}},
+ "TARGET_OUT_PRODUCT_SERVICES": {{prefix: "/etc", flags: []string{"product_services_specific"}}},
+ "TARGET_OUT_PRODUCT_SERVICES_ETC": {{prefix: "", flags: []string{"product_services_specific"}}},
+ "TARGET_OUT_VENDOR": {{prefix: "/etc", flags: []string{"proprietary"}}},
+ "TARGET_OUT_VENDOR_ETC": {{prefix: "", flags: []string{"proprietary"}}},
+ "TARGET_RECOVERY_ROOT_OUT": {{prefix: "/system/etc", flags: []string{"recovery"}}},
+}
+
+// rewriteAndroidPrebuiltEtc fixes prebuilt_etc rule
+func rewriteAndroidmkPrebuiltEtc(f *Fixer) error {
+ for _, def := range f.tree.Defs {
+ mod, ok := def.(*parser.Module)
+ if !ok {
+ continue
+ }
+
+ if mod.Type != "prebuilt_etc" && mod.Type != "prebuilt_etc_host" {
+ continue
+ }
+
+ // The rewriter converts LOCAL_SRC_FILES to `srcs` attribute. Convert
+ // it to 'src' attribute (which is where the file is installed). If the
+ // value 'srcs' is a list, we can convert it only if it contains a single
+ // element.
+ if srcs, ok := mod.GetProperty("srcs"); ok {
+ if srcList, ok := srcs.Value.(*parser.List); ok {
+ removeProperty(mod, "srcs")
+ if len(srcList.Values) == 1 {
+ mod.Properties = append(mod.Properties,
+ &parser.Property{Name: "src", NamePos: srcs.NamePos, ColonPos: srcs.ColonPos, Value: resolveLocalModule(mod, srcList.Values[0])})
+ } else if len(srcList.Values) > 1 {
+ indicateAttributeError(mod, "src", "LOCAL_SRC_FILES should contain at most one item")
+ }
+ } else if _, ok = srcs.Value.(*parser.Variable); ok {
+ removeProperty(mod, "srcs")
+ mod.Properties = append(mod.Properties,
+ &parser.Property{Name: "src", NamePos: srcs.NamePos, ColonPos: srcs.ColonPos, Value: resolveLocalModule(mod, srcs.Value)})
+ } else {
+ renameProperty(mod, "srcs", "src")
+ }
+ }
+
+ // The rewriter converts LOCAL_MODULE_PATH attribute into a struct attribute
+ // 'local_module_path'. Analyze its contents and create the correct sub_dir:,
+ // filename: and boolean attributes combination
+ const local_module_path = "local_module_path"
+ if prop_local_module_path, ok := mod.GetProperty(local_module_path); ok {
+ removeProperty(mod, local_module_path)
+ prefixVariableName := getStringProperty(prop_local_module_path, "var")
+ path := getStringProperty(prop_local_module_path, "fixed")
+ if prefixRewrites, ok := localModulePathRewrite[prefixVariableName]; ok {
+ rewritten := false
+ for _, prefixRewrite := range prefixRewrites {
+ if path == prefixRewrite.prefix {
+ rewritten = true
+ } else if trimmedPath := strings.TrimPrefix(path, prefixRewrite.prefix+"/"); trimmedPath != path {
+ makePrebuiltEtcDestination(mod, trimmedPath)
+ rewritten = true
+ }
+ if rewritten {
+ for _, flag := range prefixRewrite.flags {
+ mod.Properties = append(mod.Properties, &parser.Property{Name: flag, Value: &parser.Bool{Value: true, Token: "true"}})
+ }
+ break
+ }
+ }
+ if !rewritten {
+ expectedPrefices := ""
+ sep := ""
+ for _, prefixRewrite := range prefixRewrites {
+ expectedPrefices += sep
+ sep = ", "
+ expectedPrefices += prefixRewrite.prefix
+ }
+ return indicateAttributeError(mod, "filename",
+ "LOCAL_MODULE_PATH value under $(%s) should start with %s", prefixVariableName, expectedPrefices)
+ }
+ if prefixVariableName == "HOST_OUT" {
+ mod.Type = "prebuilt_etc_host"
+ }
+ } else {
+ return indicateAttributeError(mod, "filename", "Cannot handle $(%s) for the prebuilt_etc", prefixVariableName)
+ }
+ }
+ }
+ return nil
+}
+
func runPatchListMod(modFunc func(mod *parser.Module, buf []byte, patchlist *parser.PatchList) error) func(*Fixer) error {
return func(f *Fixer) error {
// Make sure all the offsets are accurate
diff --git a/bpfix/bpfix/bpfix_test.go b/bpfix/bpfix/bpfix_test.go
index 5224ee3a..13942235 100644
--- a/bpfix/bpfix/bpfix_test.go
+++ b/bpfix/bpfix/bpfix_test.go
@@ -692,3 +692,62 @@ func TestRewriteCtsModuleTypes(t *testing.T) {
})
}
}
+
+func TestRewritePrebuiltEtc(t *testing.T) {
+ tests := []struct {
+ name string
+ in string
+ out string
+ }{
+ {
+ name: "prebuilt_etc src",
+ in: `
+ prebuilt_etc {
+ name: "foo",
+ srcs: ["bar"],
+ }
+ `,
+ out: `prebuilt_etc {
+ name: "foo",
+ src: "bar",
+ }
+ `,
+ },
+ {
+ name: "prebuilt_etc src",
+ in: `
+ prebuilt_etc {
+ name: "foo",
+ srcs: FOO,
+ }
+ `,
+ out: `prebuilt_etc {
+ name: "foo",
+ src: FOO,
+ }
+ `,
+ },
+ {
+ name: "prebuilt_etc src",
+ in: `
+ prebuilt_etc {
+ name: "foo",
+ srcs: ["bar", "baz"],
+ }
+ `,
+ out: `prebuilt_etc {
+ name: "foo",
+ src: "ERROR: LOCAL_SRC_FILES should contain at most one item",
+
+ }
+ `,
+ },
+ }
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ runPass(t, test.in, test.out, func(fixer *Fixer) error {
+ return rewriteAndroidmkPrebuiltEtc(fixer)
+ })
+ })
+ }
+}