Merge "Add missing dependencies for python_test"
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index e7f2531..aef8944 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -56,6 +56,7 @@
 	"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 @@
 	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 @@
 	"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 @@
 	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..52b8476 100644
--- a/androidmk/cmd/androidmk/androidmk_test.go
+++ b/androidmk/cmd/androidmk/androidmk_test.go
@@ -824,6 +824,210 @@
 }
 `,
 	},
+	{
+		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/apex/apex.go b/apex/apex.go
index 321e2e8..96a4bd5 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -333,6 +333,7 @@
 	installDir string
 	class      apexFileClass
 	module     android.Module
+	symlinks   []string
 }
 
 type apexBundle struct {
@@ -396,7 +397,8 @@
 			a.properties.Multilib.Both.Binaries, target.String(),
 			a.getImageVariation(config))
 
-		if i == 0 {
+		isPrimaryAbi := i == 0
+		if isPrimaryAbi {
 			// When multilib.* is omitted for binaries, it implies
 			// multilib.first.
 			ctx.AddFarVariationDependencies([]blueprint.Variation{
@@ -571,7 +573,7 @@
 			case sharedLibTag:
 				if cc, ok := child.(*cc.Module); ok {
 					fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc)
-					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeSharedLib, cc})
+					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeSharedLib, cc, nil})
 					return true
 				} else {
 					ctx.PropertyErrorf("native_shared_libs", "%q is not a cc_library or cc_library_shared module", depName)
@@ -584,7 +586,7 @@
 						return true
 					}
 					fileToCopy, dirInApex := getCopyManifestForExecutable(cc)
-					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeExecutable, cc})
+					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeExecutable, cc, cc.Symlinks()})
 					return true
 				} else {
 					ctx.PropertyErrorf("binaries", "%q is not a cc_binary module", depName)
@@ -595,7 +597,7 @@
 					if fileToCopy == nil {
 						ctx.PropertyErrorf("java_libs", "%q is not configured to be compiled into dex", depName)
 					} else {
-						filesInfo = append(filesInfo, apexFile{fileToCopy, depName, java.Arch().ArchType, dirInApex, javaSharedLib, java})
+						filesInfo = append(filesInfo, apexFile{fileToCopy, depName, java.Arch().ArchType, dirInApex, javaSharedLib, java, nil})
 					}
 					return true
 				} else {
@@ -604,7 +606,7 @@
 			case prebuiltTag:
 				if prebuilt, ok := child.(*android.PrebuiltEtc); ok {
 					fileToCopy, dirInApex := getCopyManifestForPrebuiltEtc(prebuilt)
-					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, prebuilt.Arch().ArchType, dirInApex, etc, prebuilt})
+					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, prebuilt.Arch().ArchType, dirInApex, etc, prebuilt, nil})
 					return true
 				} else {
 					ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName)
@@ -639,7 +641,7 @@
 					}
 					depName := ctx.OtherModuleName(child)
 					fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc)
-					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeSharedLib, cc})
+					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeSharedLib, cc, nil})
 					return true
 				}
 			}
@@ -732,6 +734,10 @@
 		dest_path := filepath.Join(android.PathForModuleOut(ctx, "image"+suffix).String(), dest)
 		copyCommands = append(copyCommands, "mkdir -p "+filepath.Dir(dest_path))
 		copyCommands = append(copyCommands, "cp "+src.String()+" "+dest_path)
+		for _, sym := range a.filesInfo[i].symlinks {
+			symlinkDest := filepath.Join(filepath.Dir(dest_path), sym)
+			copyCommands = append(copyCommands, "ln -s "+filepath.Base(dest)+" "+symlinkDest)
+		}
 	}
 	implicitInputs := append(android.Paths(nil), filesToCopy...)
 	implicitInputs = append(implicitInputs, manifest)
@@ -747,6 +753,9 @@
 			pathInApex := filepath.Join(f.installDir, f.builtFile.Base())
 			if f.installDir == "bin" {
 				executablePaths = append(executablePaths, pathInApex)
+				for _, s := range f.symlinks {
+					executablePaths = append(executablePaths, filepath.Join("bin", s))
+				}
 			} else {
 				readOnlyPaths = append(readOnlyPaths, pathInApex)
 			}
@@ -879,7 +888,7 @@
 			Input:  manifest,
 			Output: copiedManifest,
 		})
-		a.filesInfo = append(a.filesInfo, apexFile{copiedManifest, ctx.ModuleName() + ".apex_manifest.json", android.Common, ".", etc, nil})
+		a.filesInfo = append(a.filesInfo, apexFile{copiedManifest, ctx.ModuleName() + ".apex_manifest.json", android.Common, ".", etc, nil, nil})
 
 		for _, fi := range a.filesInfo {
 			dir := filepath.Join("apex", ctx.ModuleName(), fi.installDir)
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 4ca5b14..7ae49f6 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -107,6 +107,16 @@
 			recovery_available: true,
 		}
 
+		cc_object {
+			name: "crtbegin_static",
+			stl: "none",
+		}
+
+		cc_object {
+			name: "crtend_android",
+			stl: "none",
+		}
+
 		llndk_library {
 			name: "libc",
 			symbol_file: "",
@@ -194,6 +204,11 @@
 			name: "myapex",
 			key: "myapex.key",
 			native_shared_libs: ["mylib"],
+			multilib: {
+				both: {
+					binaries: ["foo",],
+				}
+			}
 		}
 
 		apex_key {
@@ -210,6 +225,25 @@
 			stl: "none",
 		}
 
+		cc_binary {
+			name: "foo",
+			srcs: ["mylib.cpp"],
+			compile_multilib: "both",
+			multilib: {
+					lib32: {
+							suffix: "32",
+					},
+					lib64: {
+							suffix: "64",
+					},
+			},
+			symlinks: ["foo_link_"],
+			symlink_preferred_arch: true,
+			system_shared_libs: [],
+			static_executable: true,
+			stl: "none",
+		}
+
 		cc_library {
 			name: "mylib2",
 			srcs: ["mylib.cpp"],
@@ -237,6 +271,23 @@
 	// Ensure that the platform variant ends with _core_shared
 	ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_core_shared")
 	ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_core_shared")
+
+	// Ensure that all symlinks are present.
+	found_foo_link_64 := false
+	found_foo := false
+	for _, cmd := range strings.Split(copyCmds, " && ") {
+		if strings.HasPrefix(cmd, "ln -s foo64") {
+			if strings.HasSuffix(cmd, "bin/foo") {
+				found_foo = true
+			} else if strings.HasSuffix(cmd, "bin/foo_link_64") {
+				found_foo_link_64 = true
+			}
+		}
+	}
+	good := found_foo && found_foo_link_64
+	if !good {
+		t.Errorf("Could not find all expected symlinks! foo: %t, foo_link_64: %t. Command was %s", found_foo, found_foo_link_64, copyCmds)
+	}
 }
 
 func TestBasicZipApex(t *testing.T) {
@@ -671,17 +722,6 @@
 			system_shared_libs: [],
 			stl: "none",
 		}
-
-		cc_object {
-			name: "crtbegin_static",
-			stl: "none",
-		}
-
-		cc_object {
-			name: "crtend_android",
-			stl: "none",
-		}
-
 	`)
 
 	ldFlags := ctx.ModuleForTests("not_in_apex", "android_arm64_armv8-a_core").Rule("ld").Args["libFlags"]
diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go
index 6a75517..11f1877 100644
--- a/bpfix/bpfix/bpfix.go
+++ b/bpfix/bpfix/bpfix.go
@@ -83,6 +83,10 @@
 		fix:  rewriteJavaStaticLibs,
 	},
 	{
+		name: "rewritePrebuiltEtc",
+		fix:  rewriteAndroidmkPrebuiltEtc,
+	},
+	{
 		name: "mergeMatchingModuleProperties",
 		fix:  runPatchListMod(mergeMatchingModuleProperties),
 	},
@@ -407,6 +411,156 @@
 	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 5224ee3..1394223 100644
--- a/bpfix/bpfix/bpfix_test.go
+++ b/bpfix/bpfix/bpfix_test.go
@@ -692,3 +692,62 @@
 		})
 	}
 }
+
+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)
+			})
+		})
+	}
+}
diff --git a/cc/binary.go b/cc/binary.go
index 65e8eb5..4c86371 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -382,11 +382,8 @@
 	objs.coverageFiles = append(objs.coverageFiles, deps.WholeStaticLibObjs.coverageFiles...)
 	binary.coverageOutputFile = TransformCoverageFilesToLib(ctx, objs, builderFlags, binary.getStem(ctx))
 
-	return ret
-}
-
-func (binary *binaryDecorator) install(ctx ModuleContext, file android.Path) {
-	binary.baseInstaller.install(ctx, file)
+	// Need to determine symlinks early since some targets (ie APEX) need this
+	// information but will not call 'install'
 	for _, symlink := range binary.Properties.Symlinks {
 		binary.symlinks = append(binary.symlinks,
 			symlink+String(binary.Properties.Suffix)+ctx.toolchain().ExecutableSuffix())
@@ -401,6 +398,15 @@
 		}
 	}
 
+	return ret
+}
+
+func (binary *binaryDecorator) symlinkList() []string {
+	return binary.symlinks
+}
+
+func (binary *binaryDecorator) install(ctx ModuleContext, file android.Path) {
+	binary.baseInstaller.install(ctx, file)
 	for _, symlink := range binary.symlinks {
 		ctx.InstallSymlink(binary.baseInstaller.installDir(ctx), symlink, binary.baseInstaller.path)
 	}
diff --git a/cc/cc.go b/cc/cc.go
index 1f50976..a30708a 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -772,6 +772,15 @@
 	return name
 }
 
+func (c *Module) Symlinks() []string {
+	if p, ok := c.installer.(interface {
+		symlinkList() []string
+	}); ok {
+		return p.symlinkList()
+	}
+	return nil
+}
+
 // orderDeps reorders dependencies into a list such that if module A depends on B, then
 // A will precede B in the resultant list.
 // This is convenient for passing into a linker.
diff --git a/cc/compdb.go b/cc/compdb.go
index 4dfc55b..1102651 100644
--- a/cc/compdb.go
+++ b/cc/compdb.go
@@ -170,14 +170,14 @@
 		return
 	}
 
-	pathToCC, err := ctx.Eval(pctx, "${config.ClangBin}/")
+	rootDir := getCompdbAndroidSrcRootDirectory(ctx)
+	pathToCC, err := ctx.Eval(pctx, rootDir+"/${config.ClangBin}/")
 	ccPath := "/bin/false"
 	cxxPath := "/bin/false"
 	if err == nil {
 		ccPath = pathToCC + "clang"
 		cxxPath = pathToCC + "clang++"
 	}
-	rootDir := getCompdbAndroidSrcRootDirectory(ctx)
 	for _, src := range srcs {
 		if _, ok := builds[src.String()]; !ok {
 			builds[src.String()] = compDbEntry{
diff --git a/cc/config/global.go b/cc/config/global.go
index ff11a8a..e3d36bd 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -176,7 +176,6 @@
 			"hardware/libhardware/include",
 			"hardware/libhardware_legacy/include",
 			"hardware/ril/include",
-			"libnativehelper/include",
 			"frameworks/native/include",
 			"frameworks/native/opengl/include",
 			"frameworks/av/include",
diff --git a/cc/config/x86_linux_host.go b/cc/config/x86_linux_host.go
index 8da21b3..f072f34 100644
--- a/cc/config/x86_linux_host.go
+++ b/cc/config/x86_linux_host.go
@@ -111,14 +111,22 @@
 )
 
 const (
-	linuxGccVersion = "4.8"
+	linuxGccVersion   = "4.8.3"
+	linuxGlibcVersion = "2.17"
 )
 
 func init() {
 	pctx.StaticVariable("LinuxGccVersion", linuxGccVersion)
+	pctx.StaticVariable("LinuxGlibcVersion", linuxGlibcVersion)
+	// Most places use the full GCC version. A few only use up to the first two numbers.
+	if p := strings.Split(linuxGccVersion, "."); len(p) > 2 {
+		pctx.StaticVariable("ShortLinuxGccVersion", strings.Join(p[:2], "."))
+	} else {
+		pctx.StaticVariable("ShortLinuxGccVersion", linuxGccVersion)
+	}
 
 	pctx.SourcePathVariable("LinuxGccRoot",
-		"prebuilts/gcc/${HostPrebuiltTag}/host/x86_64-linux-glibc2.15-${LinuxGccVersion}")
+		"prebuilts/gcc/${HostPrebuiltTag}/host/x86_64-linux-glibc${LinuxGlibcVersion}-${ShortLinuxGccVersion}")
 
 	pctx.StaticVariable("LinuxGccTriple", "x86_64-linux")
 
diff --git a/scripts/system-clang-format b/scripts/system-clang-format
index 55773a2..349eed5 100644
--- a/scripts/system-clang-format
+++ b/scripts/system-clang-format
@@ -5,6 +5,7 @@
 CommentPragmas: NOLINT:.*
 DerivePointerAlignment: false
 IndentWidth: 4
+AlignAfterOpenBracket: DontAlign
 ContinuationIndentWidth: 8
 PointerAlignment: Left
 TabWidth: 4
diff --git a/ui/logger/logger.go b/ui/logger/logger.go
index c763e50..58890e9 100644
--- a/ui/logger/logger.go
+++ b/ui/logger/logger.go
@@ -73,7 +73,9 @@
 }
 
 // fatalLog is the type used when Fatal[f|ln]
-type fatalLog error
+type fatalLog struct {
+	error
+}
 
 func fileRotation(from, baseName, ext string, cur, max int) error {
 	newName := baseName + "." + strconv.Itoa(cur) + ext
@@ -273,7 +275,7 @@
 func (s *stdLogger) Fatal(v ...interface{}) {
 	output := fmt.Sprint(v...)
 	s.Output(2, output)
-	panic(fatalLog(errors.New(output)))
+	panic(fatalLog{errors.New(output)})
 }
 
 // Fatalf is equivalent to Printf() followed by a call to panic() that
@@ -281,7 +283,7 @@
 func (s *stdLogger) Fatalf(format string, v ...interface{}) {
 	output := fmt.Sprintf(format, v...)
 	s.Output(2, output)
-	panic(fatalLog(errors.New(output)))
+	panic(fatalLog{errors.New(output)})
 }
 
 // Fatalln is equivalent to Println() followed by a call to panic() that
@@ -289,7 +291,7 @@
 func (s *stdLogger) Fatalln(v ...interface{}) {
 	output := fmt.Sprintln(v...)
 	s.Output(2, output)
-	panic(fatalLog(errors.New(output)))
+	panic(fatalLog{errors.New(output)})
 }
 
 // Panic is equivalent to Print() followed by a call to panic().
diff --git a/ui/logger/logger_test.go b/ui/logger/logger_test.go
index bdf0231..044e6f0 100644
--- a/ui/logger/logger_test.go
+++ b/ui/logger/logger_test.go
@@ -196,3 +196,17 @@
 	log.Panic("Test")
 	t.Errorf("Should not get here")
 }
+
+func TestRuntimePanic(t *testing.T) {
+	defer func() {
+		if p := recover(); p == nil {
+			t.Errorf("Panic not thrown")
+		}
+	}()
+	defer Recover(func(err error) {
+		t.Errorf("Recover function should not be called")
+	})
+	var i *int
+	*i = 0
+	t.Errorf("Should not get here")
+}