Merge "Add annotation-related args to check api"
diff --git a/Android.bp b/Android.bp
index bdc34d0..5faefe6 100644
--- a/Android.bp
+++ b/Android.bp
@@ -173,6 +173,7 @@
     testSrcs: [
         "cc/cc_test.go",
         "cc/gen_test.go",
+        "cc/genrule_test.go",
         "cc/library_test.go",
         "cc/test_data_test.go",
         "cc/util_test.go",
@@ -482,7 +483,7 @@
 }
 
 cc_genrule {
-    name: "host_bionic_linker_script",
+    name: "host_bionic_linker_flags",
     host_supported: true,
     device_supported: false,
     target: {
@@ -497,7 +498,7 @@
         },
     },
     tools: ["extract_linker"],
-    cmd: "$(location) -T $(out) $(in)",
+    cmd: "$(location) -f $(out) $(in)",
     srcs: [":linker"],
-    out: ["linker.script"],
+    out: ["linker.flags"],
 }
diff --git a/android/androidmk.go b/android/androidmk.go
index 5df4a85..7030523 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -215,7 +215,7 @@
 
 		}
 
-		if amod.Arch().ArchType != ctx.Config().Targets[amod.Os().Class][0].Arch.ArchType {
+		if amod.Arch().ArchType != ctx.Config().Targets[amod.Os()][0].Arch.ArchType {
 			prefix = "2ND_" + prefix
 		}
 	}
diff --git a/android/arch.go b/android/arch.go
index 3378317..2543fca 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -194,7 +194,7 @@
 	NoOsType    OsType
 	Linux       = NewOsType("linux_glibc", Host, false)
 	Darwin      = NewOsType("darwin", Host, false)
-	LinuxBionic = NewOsType("linux_bionic", Host, true)
+	LinuxBionic = NewOsType("linux_bionic", Host, false)
 	Windows     = NewOsType("windows", HostCross, true)
 	Android     = NewOsType("android", Device, false)
 
@@ -325,37 +325,46 @@
 		return
 	}
 
-	osClasses := base.OsClassSupported()
-
 	var moduleTargets []Target
 	moduleMultiTargets := make(map[int][]Target)
 	primaryModules := make(map[int]bool)
+	osClasses := base.OsClassSupported()
 
-	for _, class := range osClasses {
-		classTargets := mctx.Config().Targets[class]
-		if len(classTargets) == 0 {
+	for _, os := range osTypeList {
+		supportedClass := false
+		for _, osClass := range osClasses {
+			if os.Class == osClass {
+				supportedClass = true
+			}
+		}
+		if !supportedClass {
+			continue
+		}
+
+		osTargets := mctx.Config().Targets[os]
+		if len(osTargets) == 0 {
 			continue
 		}
 
 		// only the primary arch in the recovery partition
-		if module.InstallInRecovery() {
-			classTargets = []Target{mctx.Config().Targets[Device][0]}
+		if os == Android && module.InstallInRecovery() {
+			osTargets = []Target{osTargets[0]}
 		}
 
 		prefer32 := false
 		if base.prefer32 != nil {
-			prefer32 = base.prefer32(mctx, base, class)
+			prefer32 = base.prefer32(mctx, base, os.Class)
 		}
 
-		multilib, extraMultilib := decodeMultilib(base, class)
-		targets, err := decodeMultilibTargets(multilib, classTargets, prefer32)
+		multilib, extraMultilib := decodeMultilib(base, os.Class)
+		targets, err := decodeMultilibTargets(multilib, osTargets, prefer32)
 		if err != nil {
 			mctx.ModuleErrorf("%s", err.Error())
 		}
 
 		var multiTargets []Target
 		if extraMultilib != "" {
-			multiTargets, err = decodeMultilibTargets(extraMultilib, classTargets, prefer32)
+			multiTargets, err = decodeMultilibTargets(extraMultilib, osTargets, prefer32)
 			if err != nil {
 				mctx.ModuleErrorf("%s", err.Error())
 			}
@@ -839,17 +848,17 @@
 			}
 
 			if (arch.ArchType == X86 && (hasArmAbi(arch) ||
-				hasArmAndroidArch(ctx.Config().Targets[Device]))) ||
+				hasArmAndroidArch(ctx.Config().Targets[Android]))) ||
 				(arch.ArchType == Arm &&
-					hasX86AndroidArch(ctx.Config().Targets[Device])) {
+					hasX86AndroidArch(ctx.Config().Targets[Android])) {
 				field := "Arm_on_x86"
 				prefix := "target.arm_on_x86"
 				a.appendProperties(ctx, genProps, targetProp, field, prefix)
 			}
 			if (arch.ArchType == X86_64 && (hasArmAbi(arch) ||
-				hasArmAndroidArch(ctx.Config().Targets[Device]))) ||
+				hasArmAndroidArch(ctx.Config().Targets[Android]))) ||
 				(arch.ArchType == Arm &&
-					hasX8664AndroidArch(ctx.Config().Targets[Device])) {
+					hasX8664AndroidArch(ctx.Config().Targets[Android])) {
 				field := "Arm_on_x86_64"
 				prefix := "target.arm_on_x86_64"
 				a.appendProperties(ctx, genProps, targetProp, field, prefix)
@@ -874,10 +883,10 @@
 }
 
 // Convert the arch product variables into a list of targets for each os class structs
-func decodeTargetProductVariables(config *config) (map[OsClass][]Target, error) {
+func decodeTargetProductVariables(config *config) (map[OsType][]Target, error) {
 	variables := config.productVariables
 
-	targets := make(map[OsClass][]Target)
+	targets := make(map[OsType][]Target)
 	var targetErr error
 
 	addTarget := func(os OsType, archName string, archVariant, cpuVariant *string, abi *[]string) {
@@ -891,7 +900,7 @@
 			return
 		}
 
-		targets[os.Class] = append(targets[os.Class],
+		targets[os] = append(targets[os],
 			Target{
 				Os:   os,
 				Arch: arch,
@@ -938,7 +947,7 @@
 				variables.DeviceSecondaryArchVariant, variables.DeviceSecondaryCpuVariant,
 				variables.DeviceSecondaryAbi)
 
-			deviceArches := targets[Device]
+			deviceArches := targets[Android]
 			if deviceArches[0].Arch.ArchType.Multilib == deviceArches[1].Arch.ArchType.Multilib {
 				deviceArches[1].Arch.Native = false
 			}
diff --git a/android/config.go b/android/config.go
index 5da1e0b..0aee0e3 100644
--- a/android/config.go
+++ b/android/config.go
@@ -90,7 +90,7 @@
 	ConfigFileName           string
 	ProductVariablesFileName string
 
-	Targets              map[OsClass][]Target
+	Targets              map[OsType][]Target
 	BuildOsVariant       string
 	BuildOsCommonVariant string
 
@@ -230,18 +230,18 @@
 	testConfig := TestConfig(buildDir, env)
 	config := testConfig.config
 
-	config.Targets = map[OsClass][]Target{
-		Device: []Target{
+	config.Targets = map[OsType][]Target{
+		Android: []Target{
 			{Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Native: true, Abi: []string{"arm64-v8a"}}},
 			{Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Native: true, Abi: []string{"armeabi-v7a"}}},
 		},
-		Host: []Target{
+		BuildOs: []Target{
 			{BuildOs, Arch{ArchType: X86_64}},
 			{BuildOs, Arch{ArchType: X86}},
 		},
 	}
 
-	config.BuildOsVariant = config.Targets[Host][0].String()
+	config.BuildOsVariant = config.Targets[BuildOs][0].String()
 
 	return testConfig
 }
@@ -304,16 +304,16 @@
 	}
 
 	if archConfig != nil {
-		deviceTargets, err := decodeArchSettings(archConfig)
+		androidTargets, err := decodeArchSettings(archConfig)
 		if err != nil {
 			return Config{}, err
 		}
-		targets[Device] = deviceTargets
+		targets[Android] = androidTargets
 	}
 
 	config.Targets = targets
-	config.BuildOsVariant = targets[Host][0].String()
-	config.BuildOsCommonVariant = getCommonTargets(targets[Host])[0].String()
+	config.BuildOsVariant = targets[BuildOs][0].String()
+	config.BuildOsCommonVariant = getCommonTargets(targets[BuildOs])[0].String()
 
 	if err := config.fromEnv(); err != nil {
 		return Config{}, err
@@ -587,7 +587,7 @@
 }
 
 func (c *config) DevicePrimaryArchType() ArchType {
-	return c.Targets[Device][0].Arch.ArchType
+	return c.Targets[Android][0].Arch.ArchType
 }
 
 func (c *config) SkipDeviceInstall() bool {
@@ -624,7 +624,7 @@
 }
 
 func (c *config) Android64() bool {
-	for _, t := range c.Targets[Device] {
+	for _, t := range c.Targets[Android] {
 		if t.Arch.ArchType.Multilib == "lib64" {
 			return true
 		}
@@ -646,10 +646,6 @@
 	return c.targetOpenJDK9
 }
 
-func (c *config) UseClangLld() bool {
-	return Bool(c.productVariables.UseClangLld)
-}
-
 func (c *config) ClangTidy() bool {
 	return Bool(c.productVariables.ClangTidy)
 }
@@ -667,8 +663,8 @@
 
 func (c *config) LibartImgDeviceBaseAddress() string {
 	archType := Common
-	if len(c.Targets[Device]) > 0 {
-		archType = c.Targets[Device][0].Arch.ArchType
+	if len(c.Targets[Android]) > 0 {
+		archType = c.Targets[Android][0].Arch.ArchType
 	}
 	switch archType {
 	default:
@@ -715,7 +711,7 @@
 
 func (c *deviceConfig) Arches() []Arch {
 	var arches []Arch
-	for _, target := range c.config.Targets[Device] {
+	for _, target := range c.config.Targets[Android] {
 		arches = append(arches, target.Arch)
 	}
 	return arches
diff --git a/android/module.go b/android/module.go
index 9d9d9a9..556c73d 100644
--- a/android/module.go
+++ b/android/module.go
@@ -1071,10 +1071,10 @@
 }
 
 func (a *androidBaseContextImpl) PrimaryArch() bool {
-	if len(a.config.Targets[a.target.Os.Class]) <= 1 {
+	if len(a.config.Targets[a.target.Os]) <= 1 {
 		return true
 	}
-	return a.target.Arch.ArchType == a.config.Targets[a.target.Os.Class][0].Arch.ArchType
+	return a.target.Arch.ArchType == a.config.Targets[a.target.Os][0].Arch.ArchType
 }
 
 func (a *androidBaseContextImpl) AConfig() Config {
diff --git a/android/paths.go b/android/paths.go
index daaf857..b22e3c7 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -725,46 +725,6 @@
 	return PathForOutput(ctx, ".intermediates", path)
 }
 
-// DistPath is a Path representing a file path rooted from the dist directory
-type DistPath struct {
-	basePath
-}
-
-func (p DistPath) withRel(rel string) DistPath {
-	p.basePath = p.basePath.withRel(rel)
-	return p
-}
-
-var _ Path = DistPath{}
-
-// PathForDist joins the provided paths and returns a DistPath that is
-// validated to not escape the dist dir.
-// On error, it will return a usable, but invalid DistPath, and report a ModuleError.
-func PathForDist(ctx PathContext, pathComponents ...string) DistPath {
-	path, err := validatePath(pathComponents...)
-	if err != nil {
-		reportPathError(ctx, err)
-	}
-	return DistPath{basePath{path, ctx.Config(), ""}}
-}
-
-func (p DistPath) writablePath() {}
-
-func (p DistPath) Valid() bool {
-	return p.config.productVariables.DistDir != nil && *p.config.productVariables.DistDir != ""
-}
-
-func (p DistPath) String() string {
-	if !p.Valid() {
-		panic("Requesting an invalid path")
-	}
-	return filepath.Join(*p.config.productVariables.DistDir, p.path)
-}
-
-func (p DistPath) RelPathString() string {
-	return p.path
-}
-
 // ModuleSrcPath is a Path representing a file rooted from a module's local source dir
 type ModuleSrcPath struct {
 	SourcePath
diff --git a/android/variable.go b/android/variable.go
index 5c4d491..476171b 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -201,8 +201,6 @@
 	ProductPath         *string `json:",omitempty"`
 	ProductServicesPath *string `json:",omitempty"`
 
-	UseClangLld *bool `json:",omitempty"`
-
 	ClangTidy  *bool   `json:",omitempty"`
 	TidyChecks *string `json:",omitempty"`
 
@@ -228,7 +226,6 @@
 	Product_is_iot *bool `json:",omitempty"`
 
 	DeviceKernelHeaders []string `json:",omitempty"`
-	DistDir             *string  `json:",omitempty"`
 
 	ExtraVndkVersions []string `json:",omitempty"`
 
diff --git a/cc/binary.go b/cc/binary.go
index 5fa501e..15db2ad 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -15,6 +15,8 @@
 package cc
 
 import (
+	"github.com/google/blueprint"
+
 	"android/soong/android"
 )
 
@@ -154,7 +156,8 @@
 		}
 
 		if ctx.Os() == android.LinuxBionic && !binary.static() {
-			deps.LinkerScript = "host_bionic_linker_script"
+			deps.DynamicLinker = "linker"
+			deps.LinkerFlagsFile = "host_bionic_linker_flags"
 		}
 	}
 
@@ -244,14 +247,23 @@
 					switch ctx.Os() {
 					case android.Android:
 						flags.DynamicLinker = "/system/bin/linker"
+						if flags.Toolchain.Is64Bit() {
+							flags.DynamicLinker += "64"
+						}
 					case android.LinuxBionic:
 						flags.DynamicLinker = ""
 					default:
 						ctx.ModuleErrorf("unknown dynamic linker")
 					}
-					if flags.Toolchain.Is64Bit() {
-						flags.DynamicLinker += "64"
-					}
+				}
+
+				if ctx.Os() == android.LinuxBionic {
+					// Use the dlwrap entry point, but keep _start around so
+					// that it can be used by host_bionic_inject
+					flags.LdFlags = append(flags.LdFlags,
+						"-Wl,--entry=__dlwrap__start",
+						"-Wl,--undefined=_start",
+					)
 				}
 			}
 
@@ -262,7 +274,6 @@
 				"-Wl,--gc-sections",
 				"-Wl,-z,nocopyreloc",
 			)
-
 		}
 	} else {
 		if binary.static() {
@@ -288,13 +299,15 @@
 	sharedLibs := deps.SharedLibs
 	sharedLibs = append(sharedLibs, deps.LateSharedLibs...)
 
-	if deps.LinkerScript.Valid() {
-		flags.LdFlags = append(flags.LdFlags, "-Wl,-T,"+deps.LinkerScript.String())
-		linkerDeps = append(linkerDeps, deps.LinkerScript.Path())
+	if deps.LinkerFlagsFile.Valid() {
+		flags.LdFlags = append(flags.LdFlags, "$$(cat "+deps.LinkerFlagsFile.String()+")")
+		linkerDeps = append(linkerDeps, deps.LinkerFlagsFile.Path())
 	}
 
 	if flags.DynamicLinker != "" {
-		flags.LdFlags = append(flags.LdFlags, " -Wl,-dynamic-linker,"+flags.DynamicLinker)
+		flags.LdFlags = append(flags.LdFlags, "-Wl,-dynamic-linker,"+flags.DynamicLinker)
+	} else if ctx.toolchain().Bionic() && !binary.static() {
+		flags.LdFlags = append(flags.LdFlags, "-Wl,--no-dynamic-linker")
 	}
 
 	builderFlags := flagsToBuilderFlags(flags)
@@ -323,6 +336,17 @@
 		binary.injectVersionSymbol(ctx, outputFile, versionedOutputFile)
 	}
 
+	if ctx.Os() == android.LinuxBionic && !binary.static() {
+		injectedOutputFile := outputFile
+		outputFile = android.PathForModuleOut(ctx, "prelinker", fileName)
+
+		if !deps.DynamicLinker.Valid() {
+			panic("Non-static host bionic modules must have a dynamic linker")
+		}
+
+		binary.injectHostBionicLinkerSymbols(ctx, outputFile, deps.DynamicLinker.Path(), injectedOutputFile)
+	}
+
 	linkerDeps = append(linkerDeps, deps.SharedLibsDeps...)
 	linkerDeps = append(linkerDeps, deps.LateSharedLibsDeps...)
 	linkerDeps = append(linkerDeps, objs.tidyFiles...)
@@ -367,3 +391,26 @@
 func (binary *binaryDecorator) hostToolPath() android.OptionalPath {
 	return binary.toolPath
 }
+
+func init() {
+	pctx.HostBinToolVariable("hostBionicSymbolsInjectCmd", "host_bionic_inject")
+}
+
+var injectHostBionicSymbols = pctx.AndroidStaticRule("injectHostBionicSymbols",
+	blueprint.RuleParams{
+		Command:     "$hostBionicSymbolsInjectCmd -i $in -l $linker -o $out",
+		CommandDeps: []string{"$hostBionicSymbolsInjectCmd"},
+	}, "linker")
+
+func (binary *binaryDecorator) injectHostBionicLinkerSymbols(ctx ModuleContext, in, linker android.Path, out android.WritablePath) {
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        injectHostBionicSymbols,
+		Description: "inject host bionic symbols",
+		Input:       in,
+		Implicit:    linker,
+		Output:      out,
+		Args: map[string]string{
+			"linker": linker.String(),
+		},
+	})
+}
diff --git a/cc/builder.go b/cc/builder.go
index d9a6cae..3d12538 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -191,11 +191,8 @@
 		func(ctx android.PackageRuleContext) blueprint.RuleParams {
 			// TODO(b/78139997): Add -check-all-apis back
 			commandStr := "($sAbiDiffer $allowFlags -lib $libName -arch $arch -o ${out} -new $in -old $referenceDump)"
-			distAbiDiffDir := android.PathForDist(ctx, "abidiffs")
 			commandStr += "|| (echo ' ---- Please update abi references by running $$ANDROID_BUILD_TOP/development/vndk/tools/header-checker/utils/create_reference_dumps.py -l ${libName} ----'"
-			if distAbiDiffDir.Valid() {
-				commandStr += " && (mkdir -p " + distAbiDiffDir.String() + " && cp ${out} " + distAbiDiffDir.String() + ")"
-			}
+			commandStr += " && (mkdir -p $$DIST_DIR/abidiffs && cp ${out} $$DIST_DIR/abidiff/)"
 			commandStr += " && exit 1)"
 			return blueprint.RuleParams{
 				Command:     commandStr,
diff --git a/cc/cc.go b/cc/cc.go
index 6320b9c..8b68489 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -83,7 +83,10 @@
 	ReexportGeneratedHeaders []string
 
 	CrtBegin, CrtEnd string
-	LinkerScript     string
+
+	// Used for host bionic
+	LinkerFlagsFile string
+	DynamicLinker   string
 }
 
 type PathDeps struct {
@@ -108,7 +111,12 @@
 
 	// Paths to crt*.o files
 	CrtBegin, CrtEnd android.OptionalPath
-	LinkerScript     android.OptionalPath
+
+	// Path to the file container flags to use with the linker
+	LinkerFlagsFile android.OptionalPath
+
+	// Path to the dynamic linker binary
+	DynamicLinker android.OptionalPath
 }
 
 type Flags struct {
@@ -306,7 +314,8 @@
 	objDepTag             = dependencyTag{name: "obj"}
 	crtBeginDepTag        = dependencyTag{name: "crtbegin"}
 	crtEndDepTag          = dependencyTag{name: "crtend"}
-	linkerScriptDepTag    = dependencyTag{name: "linker script"}
+	linkerFlagsDepTag     = dependencyTag{name: "linker flags file"}
+	dynamicLinkerDepTag   = dependencyTag{name: "dynamic linker"}
 	reuseObjTag           = dependencyTag{name: "reuse objects"}
 	ndkStubDepTag         = dependencyTag{name: "ndk stub", library: true}
 	ndkLateStubDepTag     = dependencyTag{name: "ndk late stub", library: true}
@@ -1062,8 +1071,11 @@
 	if deps.CrtEnd != "" {
 		actx.AddVariationDependencies(nil, crtEndDepTag, deps.CrtEnd)
 	}
-	if deps.LinkerScript != "" {
-		actx.AddDependency(c, linkerScriptDepTag, deps.LinkerScript)
+	if deps.LinkerFlagsFile != "" {
+		actx.AddDependency(c, linkerFlagsDepTag, deps.LinkerFlagsFile)
+	}
+	if deps.DynamicLinker != "" {
+		actx.AddDependency(c, dynamicLinkerDepTag, deps.DynamicLinker)
 	}
 
 	version := ctx.sdkVersion()
@@ -1257,13 +1269,13 @@
 				} else {
 					ctx.ModuleErrorf("module %q is not a genrule", depName)
 				}
-			case linkerScriptDepTag:
+			case linkerFlagsDepTag:
 				if genRule, ok := dep.(genrule.SourceFileGenerator); ok {
 					files := genRule.GeneratedSourceFiles()
 					if len(files) == 1 {
-						depPaths.LinkerScript = android.OptionalPathForPath(files[0])
+						depPaths.LinkerFlagsFile = android.OptionalPathForPath(files[0])
 					} else if len(files) > 1 {
-						ctx.ModuleErrorf("module %q can only generate a single file if used for a linker script", depName)
+						ctx.ModuleErrorf("module %q can only generate a single file if used for a linker flag file", depName)
 					}
 				} else {
 					ctx.ModuleErrorf("module %q is not a genrule", depName)
@@ -1358,6 +1370,8 @@
 			depPaths.CrtBegin = linkFile
 		case crtEndDepTag:
 			depPaths.CrtEnd = linkFile
+		case dynamicLinkerDepTag:
+			depPaths.DynamicLinker = linkFile
 		}
 
 		switch depTag {
diff --git a/cc/compiler.go b/cc/compiler.go
index 68d8593..5ac5d79 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -224,6 +224,10 @@
 		deps = protoDeps(ctx, deps, &compiler.Proto, Bool(compiler.Properties.Proto.Static))
 	}
 
+	if compiler.hasSrcExt(".sysprop") {
+		deps.SharedLibs = append(deps.SharedLibs, "libbase")
+	}
+
 	if Bool(compiler.Properties.Openmp) {
 		deps.StaticLibs = append(deps.StaticLibs, "libomp")
 	}
@@ -387,7 +391,7 @@
 		flags.GlobalFlags = append([]string{"${config.ClangExternalCflags}"}, flags.GlobalFlags...)
 	}
 
-	if ctx.Device() {
+	if tc.Bionic() {
 		if Bool(compiler.Properties.Rtti) {
 			flags.CppFlags = append(flags.CppFlags, "-frtti")
 		} else {
@@ -489,6 +493,11 @@
 		flags = rsFlags(ctx, flags, &compiler.Properties)
 	}
 
+	if compiler.hasSrcExt(".sysprop") {
+		flags.GlobalFlags = append(flags.GlobalFlags,
+			"-I"+android.PathForModuleGen(ctx, "sysprop", "include").String())
+	}
+
 	if len(compiler.Properties.Srcs) > 0 {
 		module := ctx.ModuleDir() + "/Android.bp:" + ctx.ModuleName()
 		if inList("-Wno-error", flags.CFlags) || inList("-Wno-error", flags.CppFlags) {
diff --git a/cc/config/x86_linux_bionic_host.go b/cc/config/x86_linux_bionic_host.go
index 8a12523..5fb88e6 100644
--- a/cc/config/x86_linux_bionic_host.go
+++ b/cc/config/x86_linux_bionic_host.go
@@ -139,6 +139,10 @@
 	return true
 }
 
+func (toolchainLinuxBionic) LibclangRuntimeLibraryArch() string {
+	return "x86_64"
+}
+
 var toolchainLinuxBionicSingleton Toolchain = &toolchainLinuxBionic{}
 
 func linuxBionicToolchainFactory(arch android.Arch) Toolchain {
diff --git a/cc/gen.go b/cc/gen.go
index 487f662..29a2bb2 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -19,6 +19,8 @@
 // functions.
 
 import (
+	"path/filepath"
+
 	"github.com/google/blueprint"
 
 	"android/soong/android"
@@ -30,6 +32,7 @@
 	pctx.SourcePathVariable("yaccDataDir", "prebuilts/build-tools/common/bison")
 
 	pctx.HostBinToolVariable("aidlCmd", "aidl-cpp")
+	pctx.HostBinToolVariable("syspropCmd", "sysprop_cpp")
 }
 
 var (
@@ -55,6 +58,13 @@
 		},
 		"aidlFlags", "outDir")
 
+	sysprop = pctx.AndroidStaticRule("sysprop",
+		blueprint.RuleParams{
+			Command:     "$syspropCmd --header-output-dir=$headerOutDir --source-output-dir=$srcOutDir --include-name=$includeName $in",
+			CommandDeps: []string{"$syspropCmd"},
+		},
+		"headerOutDir", "srcOutDir", "includeName")
+
 	windmc = pctx.AndroidStaticRule("windmc",
 		blueprint.RuleParams{
 			Command:     "$windmcCmd -r$$(dirname $out) -h$$(dirname $out) $in",
@@ -82,7 +92,6 @@
 }
 
 func genAidl(ctx android.ModuleContext, aidlFile android.Path, outFile android.ModuleGenPath, aidlFlags string) android.Paths {
-
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        aidl,
 		Description: "aidl " + aidlFile.Rel(),
@@ -107,6 +116,26 @@
 	})
 }
 
+func genSysprop(ctx android.ModuleContext, syspropFile android.Path) (android.Path, android.Path) {
+	headerFile := android.PathForModuleGen(ctx, "sysprop", "include", syspropFile.Rel()+".h")
+	cppFile := android.PathForModuleGen(ctx, "sysprop", syspropFile.Rel()+".cpp")
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:           sysprop,
+		Description:    "sysprop " + syspropFile.Rel(),
+		Output:         cppFile,
+		ImplicitOutput: headerFile,
+		Input:          syspropFile,
+		Args: map[string]string{
+			"headerOutDir": filepath.Dir(headerFile.String()),
+			"srcOutDir":    filepath.Dir(cppFile.String()),
+			"includeName":  syspropFile.Rel() + ".h",
+		},
+	})
+
+	return cppFile, headerFile
+}
+
 func genWinMsg(ctx android.ModuleContext, srcFile android.Path, flags builderFlags) (android.Path, android.Path) {
 	headerFile := android.GenPathWithExt(ctx, "windmc", srcFile, "h")
 	rcFile := android.GenPathWithExt(ctx, "windmc", srcFile, "rc")
@@ -169,6 +198,10 @@
 			rcFile, headerFile := genWinMsg(ctx, srcFile, buildFlags)
 			srcFiles[i] = rcFile
 			deps = append(deps, headerFile)
+		case ".sysprop":
+			cppFile, headerFile := genSysprop(ctx, srcFile)
+			srcFiles[i] = cppFile
+			deps = append(deps, headerFile)
 		}
 	}
 
diff --git a/cc/genrule_test.go b/cc/genrule_test.go
new file mode 100644
index 0000000..92024ac
--- /dev/null
+++ b/cc/genrule_test.go
@@ -0,0 +1,88 @@
+// Copyright 2018 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import (
+	"reflect"
+	"testing"
+
+	"android/soong/android"
+)
+
+func testGenruleContext(config android.Config, bp string,
+	fs map[string][]byte) *android.TestContext {
+
+	ctx := android.NewTestArchContext()
+	ctx.RegisterModuleType("cc_genrule", android.ModuleFactoryAdaptor(genRuleFactory))
+	ctx.Register()
+
+	mockFS := map[string][]byte{
+		"Android.bp": []byte(bp),
+		"tool":       nil,
+		"foo":        nil,
+		"bar":        nil,
+	}
+
+	for k, v := range fs {
+		mockFS[k] = v
+	}
+
+	ctx.MockFileSystem(mockFS)
+
+	return ctx
+}
+
+func TestArchGenruleCmd(t *testing.T) {
+	config := android.TestArchConfig(buildDir, nil)
+	bp := `
+				cc_genrule {
+					name: "gen",
+					tool_files: ["tool"],
+					cmd: "$(location tool) $(in) $(out)",
+					arch: {
+						arm: {
+							srcs: ["foo"],
+							out: ["out_arm"],
+						},
+						arm64: {
+							srcs: ["bar"],
+							out: ["out_arm64"],
+						},
+					},
+				}
+			`
+
+	ctx := testGenruleContext(config, bp, nil)
+
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+	if errs == nil {
+		_, errs = ctx.PrepareBuildActions(config)
+	}
+	if errs != nil {
+		t.Fatal(errs)
+	}
+
+	gen := ctx.ModuleForTests("gen", "android_arm_armv7-a-neon").Output("out_arm")
+	expected := []string{"foo"}
+	if !reflect.DeepEqual(expected, gen.Inputs.Strings()) {
+		t.Errorf(`want arm inputs %v, got %v`, expected, gen.Inputs.Strings())
+	}
+
+	gen = ctx.ModuleForTests("gen", "android_arm64_armv8-a").Output("out_arm64")
+	expected = []string{"bar"}
+	if !reflect.DeepEqual(expected, gen.Inputs.Strings()) {
+		t.Errorf(`want arm64 inputs %v, got %v`, expected, gen.Inputs.Strings())
+	}
+}
diff --git a/cc/library.go b/cc/library.go
index 9eb3f47..920292d 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -678,6 +678,14 @@
 		}
 	}
 
+	if library.baseCompiler.hasSrcExt(".sysprop") {
+		flags := []string{
+			"-I" + android.PathForModuleGen(ctx, "sysprop", "include").String(),
+		}
+		library.reexportFlags(flags)
+		library.reuseExportedFlags = append(library.reuseExportedFlags, flags...)
+	}
+
 	return out
 }
 
diff --git a/cc/linker.go b/cc/linker.go
index 2e1828a..28f4747 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -289,7 +289,7 @@
 	if linker.Properties.Use_clang_lld != nil {
 		return Bool(linker.Properties.Use_clang_lld)
 	}
-	return ctx.Config().UseClangLld()
+	return true
 }
 
 // ModuleContext extends BaseModuleContext
diff --git a/cc/lto.go b/cc/lto.go
index fd2a869..52b9a34 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -76,7 +76,7 @@
 	if lto.Properties.Use_clang_lld != nil {
 		return Bool(lto.Properties.Use_clang_lld)
 	}
-	return ctx.Config().UseClangLld()
+	return true
 }
 
 func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags {
diff --git a/cc/makevars.go b/cc/makevars.go
index b590786..32674a9 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -172,13 +172,13 @@
 	sort.Strings(ndkMigratedLibs)
 	ctx.Strict("NDK_MIGRATED_LIBS", strings.Join(ndkMigratedLibs, " "))
 
-	hostTargets := ctx.Config().Targets[android.Host]
+	hostTargets := ctx.Config().Targets[android.BuildOs]
 	makeVarsToolchain(ctx, "", hostTargets[0])
 	if len(hostTargets) > 1 {
 		makeVarsToolchain(ctx, "2ND_", hostTargets[1])
 	}
 
-	crossTargets := ctx.Config().Targets[android.HostCross]
+	crossTargets := ctx.Config().Targets[android.Windows]
 	if len(crossTargets) > 0 {
 		makeVarsToolchain(ctx, "", crossTargets[0])
 		if len(crossTargets) > 1 {
@@ -186,7 +186,7 @@
 		}
 	}
 
-	deviceTargets := ctx.Config().Targets[android.Device]
+	deviceTargets := ctx.Config().Targets[android.Android]
 	makeVarsToolchain(ctx, "", deviceTargets[0])
 	if len(deviceTargets) > 1 {
 		makeVarsToolchain(ctx, "2ND_", deviceTargets[1])
diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go
index 1cd4829..cdf63d8 100644
--- a/cc/ndk_headers.go
+++ b/cc/ndk_headers.go
@@ -278,11 +278,7 @@
 
 	module.AddProperties(&module.properties)
 
-	// Host module rather than device module because device module install steps
-	// do not get run when embedded in make. We're not any of the existing
-	// module types that can be exposed via the Android.mk exporter, so just use
-	// a host module.
-	android.InitAndroidArchModule(module, android.HostSupportedNoCross, android.MultilibFirst)
+	android.InitAndroidModule(module)
 
 	return module
 }
@@ -362,11 +358,7 @@
 
 	module.AddProperties(&module.properties)
 
-	// Host module rather than device module because device module install steps
-	// do not get run when embedded in make. We're not any of the existing
-	// module types that can be exposed via the Android.mk exporter, so just use
-	// a host module.
-	android.InitAndroidArchModule(module, android.HostSupportedNoCross, android.MultilibFirst)
+	android.InitAndroidModule(module)
 
 	return module
 }
diff --git a/cc/test.go b/cc/test.go
index 96049db..e6251d3 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -31,6 +31,12 @@
 	Isolated *bool
 }
 
+// Test option struct.
+type TestOptions struct {
+	// the UID that you want to run in device.
+	Run_test_as string `android:"arch_variant"`
+}
+
 type TestBinaryProperties struct {
 	// Create a separate binary for each source file.  Useful when there is
 	// global state that can not be torn down and reset between each test suite.
@@ -56,6 +62,9 @@
 	// the name of the test configuration template (for example "AndroidTestTemplate.xml") that
 	// should be installed with the module.
 	Test_config_template *string `android:"arch_variant"`
+
+	// Test options.
+	Test_options *TestOptions
 }
 
 func init() {
@@ -244,8 +253,16 @@
 
 func (test *testBinary) install(ctx ModuleContext, file android.Path) {
 	test.data = ctx.ExpandSources(test.Properties.Data, nil)
+
+	// Append new line in template like below
+	// <option name="run-test-as" value="1234" />
+	optionsMap := map[string]string{}
+	if test.Properties.Test_options != nil {
+		optionsMap["run-test-as"] = string(test.Properties.Test_options.Run_test_as)
+	}
+
 	test.testConfig = tradefed.AutoGenNativeTestConfig(ctx, test.Properties.Test_config,
-		test.Properties.Test_config_template)
+		test.Properties.Test_config_template, optionsMap)
 
 	test.binaryDecorator.baseInstaller.dir = "nativetest"
 	test.binaryDecorator.baseInstaller.dir64 = "nativetest64"
diff --git a/cmd/extract_linker/main.go b/cmd/extract_linker/main.go
index 3f24ab2..ea0bf4e 100644
--- a/cmd/extract_linker/main.go
+++ b/cmd/extract_linker/main.go
@@ -13,7 +13,7 @@
 // limitations under the License.
 
 // This tool extracts ELF LOAD segments from our linker binary, and produces an
-// assembly file and linker script which will embed those segments as sections
+// assembly file and linker flags which will embed those segments as sections
 // in another binary.
 package main
 
@@ -26,38 +26,15 @@
 	"io/ioutil"
 	"log"
 	"os"
-	"text/template"
+	"strings"
 )
 
-var linkerScriptTemplate = template.Must(template.New("linker_script").Parse(`
-ENTRY(__dlwrap__start)
-SECTIONS {
-	__dlwrap_original_start = _start;
-	/DISCARD/ : { *(.interp) }
-
-{{range .}}
-	. = {{ printf "0x%x" .Vaddr }};
-	{{.Name}} : { KEEP(*({{.Name}})) }
-{{end}}
-
-	.text : { *(.text .text.*) }
-	.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
-	.data : { *(.data .data.* .gnu.linkonce.d.*) }
-	.bss : { *(.dynbss) *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) }
-}
-`))
-
-type LinkerSection struct {
-	Name  string
-	Vaddr uint64
-}
-
 func main() {
 	var asmPath string
-	var scriptPath string
+	var flagsPath string
 
 	flag.StringVar(&asmPath, "s", "", "Path to save the assembly file")
-	flag.StringVar(&scriptPath, "T", "", "Path to save the linker script")
+	flag.StringVar(&flagsPath, "f", "", "Path to save the linker flags")
 	flag.Parse()
 
 	f, err := os.Open(flag.Arg(0))
@@ -72,19 +49,21 @@
 	}
 
 	asm := &bytes.Buffer{}
-
-	fmt.Fprintln(asm, ".globl __dlwrap_linker_entry")
-	fmt.Fprintf(asm, ".set __dlwrap_linker_entry, 0x%x\n\n", ef.Entry)
-
 	baseLoadAddr := uint64(0x1000)
-	sections := []LinkerSection{}
 	load := 0
+	linkFlags := []string{}
+
+	fmt.Fprintln(asm, ".globl __dlwrap_linker_offset")
+	fmt.Fprintf(asm, ".set __dlwrap_linker_offset, 0x%x\n", baseLoadAddr)
+
 	for _, prog := range ef.Progs {
 		if prog.Type != elf.PT_LOAD {
 			continue
 		}
 
 		sectionName := fmt.Sprintf(".linker.sect%d", load)
+		symName := fmt.Sprintf("__dlwrap_linker_sect%d", load)
+
 		flags := ""
 		if prog.Flags&elf.PF_W != 0 {
 			flags += "w"
@@ -94,10 +73,12 @@
 		}
 		fmt.Fprintf(asm, ".section %s, \"a%s\"\n", sectionName, flags)
 
-		if load == 0 {
-			fmt.Fprintln(asm, ".globl __dlwrap_linker_code_start")
-			fmt.Fprintln(asm, "__dlwrap_linker_code_start:")
-		}
+		fmt.Fprintf(asm, ".globl %s\n%s:\n\n", symName, symName)
+
+		linkFlags = append(linkFlags,
+			fmt.Sprintf("-Wl,--undefined=%s", symName),
+			fmt.Sprintf("-Wl,--section-start=%s=0x%x",
+				sectionName, baseLoadAddr+prog.Vaddr))
 
 		buffer, _ := ioutil.ReadAll(prog.Open())
 		bytesToAsm(asm, buffer)
@@ -113,11 +94,6 @@
 		}
 		fmt.Fprintln(asm)
 
-		sections = append(sections, LinkerSection{
-			Name:  sectionName,
-			Vaddr: baseLoadAddr + prog.Vaddr,
-		})
-
 		load += 1
 	}
 
@@ -127,13 +103,10 @@
 		}
 	}
 
-	if scriptPath != "" {
-		buf := &bytes.Buffer{}
-		if err := linkerScriptTemplate.Execute(buf, sections); err != nil {
-			log.Fatalf("Failed to create linker script: %v", err)
-		}
-		if err := ioutil.WriteFile(scriptPath, buf.Bytes(), 0777); err != nil {
-			log.Fatalf("Unable to write %q: %v", scriptPath, err)
+	if flagsPath != "" {
+		flags := strings.Join(linkFlags, " ")
+		if err := ioutil.WriteFile(flagsPath, []byte(flags), 0777); err != nil {
+			log.Fatalf("Unable to write %q: %v", flagsPath, err)
 		}
 	}
 }
diff --git a/cmd/symbol_inject/Android.bp b/cmd/host_bionic_inject/Android.bp
similarity index 63%
copy from cmd/symbol_inject/Android.bp
copy to cmd/host_bionic_inject/Android.bp
index a2ea12b..acce683 100644
--- a/cmd/symbol_inject/Android.bp
+++ b/cmd/host_bionic_inject/Android.bp
@@ -13,20 +13,7 @@
 // limitations under the License.
 
 blueprint_go_binary {
-    name: "symbol_inject",
-    srcs: [
-        "symbol_inject.go",
-        "elf.go",
-        "macho.go",
-        "pe.go",
-    ],
-    testSrcs: [
-        "elf_symboldata_test.go",
-        "elf_test.go",
-        "macho_symboldata_test.go",
-        "macho_test.go",
-        "pe_symboldata_test.go",
-        "pe_test.go",
-        "symbol_inject_test.go",
-    ],
+    name: "host_bionic_inject",
+    deps: ["soong-symbol_inject"],
+    srcs: ["host_bionic_inject.go"],
 }
diff --git a/cmd/host_bionic_inject/host_bionic_inject.go b/cmd/host_bionic_inject/host_bionic_inject.go
new file mode 100644
index 0000000..0dabbba
--- /dev/null
+++ b/cmd/host_bionic_inject/host_bionic_inject.go
@@ -0,0 +1,174 @@
+// Copyright 2018 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Verifies a host bionic executable with an embedded linker, then injects
+// the address of the _start function for the linker_wrapper to use.
+package main
+
+import (
+	"debug/elf"
+	"flag"
+	"fmt"
+	"io"
+	"os"
+
+	"android/soong/symbol_inject"
+)
+
+func main() {
+	var inputFile, linkerFile, outputFile string
+
+	flag.StringVar(&inputFile, "i", "", "Input file")
+	flag.StringVar(&linkerFile, "l", "", "Linker file")
+	flag.StringVar(&outputFile, "o", "", "Output file")
+	flag.Parse()
+
+	if inputFile == "" || linkerFile == "" || outputFile == "" || flag.NArg() != 0 {
+		flag.Usage()
+		os.Exit(1)
+	}
+
+	r, err := os.Open(inputFile)
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err.Error())
+		os.Exit(2)
+	}
+	defer r.Close()
+
+	file, err := symbol_inject.OpenFile(r)
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err.Error())
+		os.Exit(3)
+	}
+
+	linker, err := elf.Open(linkerFile)
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err.Error())
+		os.Exit(4)
+	}
+
+	start_addr, err := parseElf(r, linker)
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err.Error())
+		os.Exit(5)
+	}
+
+	w, err := os.OpenFile(outputFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0777)
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err.Error())
+		os.Exit(6)
+	}
+	defer w.Close()
+
+	err = symbol_inject.InjectUint64Symbol(file, w, "__dlwrap_original_start", start_addr)
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err.Error())
+		os.Exit(7)
+	}
+}
+
+// Check the ELF file, and return the address to the _start function
+func parseElf(r io.ReaderAt, linker *elf.File) (uint64, error) {
+	file, err := elf.NewFile(r)
+	if err != nil {
+		return 0, err
+	}
+
+	symbols, err := file.Symbols()
+	if err != nil {
+		return 0, err
+	}
+
+	for _, prog := range file.Progs {
+		if prog.Type == elf.PT_INTERP {
+			return 0, fmt.Errorf("File should not have a PT_INTERP header")
+		}
+	}
+
+	if dlwrap_start, err := findSymbol(symbols, "__dlwrap__start"); err != nil {
+		return 0, err
+	} else if dlwrap_start.Value != file.Entry {
+		return 0, fmt.Errorf("Expected file entry(0x%x) to point to __dlwrap_start(0x%x)",
+			file.Entry, dlwrap_start.Value)
+	}
+
+	err = checkLinker(file, linker, symbols)
+	if err != nil {
+		return 0, err
+	}
+
+	start, err := findSymbol(symbols, "_start")
+	if err != nil {
+		return 0, fmt.Errorf("Failed to find _start symbol")
+	}
+	return start.Value, nil
+}
+
+func findSymbol(symbols []elf.Symbol, name string) (elf.Symbol, error) {
+	for _, sym := range symbols {
+		if sym.Name == name {
+			return sym, nil
+		}
+	}
+	return elf.Symbol{}, fmt.Errorf("Failed to find symbol %q", name)
+}
+
+// Check that all of the PT_LOAD segments have been embedded properly
+func checkLinker(file, linker *elf.File, fileSyms []elf.Symbol) error {
+	dlwrap_linker_offset, err := findSymbol(fileSyms, "__dlwrap_linker_offset")
+	if err != nil {
+		return err
+	}
+
+	for i, lprog := range linker.Progs {
+		if lprog.Type != elf.PT_LOAD {
+			continue
+		}
+
+		found := false
+		for j, prog := range file.Progs {
+			if prog.Type != elf.PT_LOAD {
+				continue
+			}
+
+			if lprog.Vaddr+dlwrap_linker_offset.Value != prog.Vaddr {
+				continue
+			}
+			found = true
+
+			if lprog.Memsz != prog.Memsz {
+				return fmt.Errorf("Linker prog %d (0x%x) memsz (0x%x) does not match (0x%x)",
+					i, lprog.Vaddr, lprog.Memsz, prog.Memsz)
+			}
+
+			// The linker shouldn't be using BSS, since only one
+			// BSS section is supported per ELF file.
+			if prog.Memsz != prog.Filesz {
+				return fmt.Errorf("Embedded prog %d (0x%x) memsz (0x%x) does not match filesz (0x%x)",
+					j, prog.Vaddr, prog.Memsz, prog.Filesz)
+			}
+
+			if lprog.Flags != prog.Flags {
+				return fmt.Errorf("Linker prog %d (0x%x) flags (%s) do not match (%s)",
+					i, lprog.Vaddr, lprog.Flags, prog.Flags)
+			}
+		}
+		if !found {
+			return fmt.Errorf("Linker prog %d (0x%x) not found at offset 0x%x",
+				i, lprog.Vaddr, dlwrap_linker_offset.Value)
+		}
+	}
+
+	return nil
+}
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 2824e49..e6c6efd 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -87,7 +87,7 @@
 	Export_include_dirs []string
 
 	// list of input files
-	Srcs []string
+	Srcs []string `android:"arch_variant"`
 }
 
 type Module struct {
@@ -504,7 +504,7 @@
 
 type genRuleProperties struct {
 	// names of the output files that will be generated
-	Out []string
+	Out []string `android:"arch_variant"`
 }
 
 var Bool = proptools.Bool
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index 7e16ce1..a99fa18 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -27,7 +27,7 @@
 
 func setUp() {
 	var err error
-	buildDir, err = ioutil.TempDir("", "soong_java_test")
+	buildDir, err = ioutil.TempDir("", "genrule_test")
 	if err != nil {
 		panic(err)
 	}
diff --git a/java/gen.go b/java/gen.go
index a993829..993e6d1 100644
--- a/java/gen.go
+++ b/java/gen.go
@@ -26,6 +26,7 @@
 
 func init() {
 	pctx.HostBinToolVariable("aidlCmd", "aidl")
+	pctx.HostBinToolVariable("syspropCmd", "sysprop_java")
 	pctx.SourcePathVariable("logtagsCmd", "build/tools/java-event-log-tags.py")
 	pctx.SourcePathVariable("mergeLogtagsCmd", "build/tools/merge-event-log-tags.py")
 }
@@ -49,6 +50,17 @@
 			Command:     "$mergeLogtagsCmd -o $out $in",
 			CommandDeps: []string{"$mergeLogtagsCmd"},
 		})
+
+	sysprop = pctx.AndroidStaticRule("sysprop",
+		blueprint.RuleParams{
+			Command: `rm -rf $out.tmp && mkdir -p $out.tmp && ` +
+				`$syspropCmd --java-output-dir $out.tmp $in && ` +
+				`${config.SoongZipCmd} -jar -o $out -C $out.tmp -D $out.tmp && rm -rf $out.tmp`,
+			CommandDeps: []string{
+				"$syspropCmd",
+				"${config.SoongZipCmd}",
+			},
+		})
 )
 
 func genAidl(ctx android.ModuleContext, aidlFile android.Path, aidlFlags string) android.Path {
@@ -82,6 +94,19 @@
 	return javaFile
 }
 
+func genSysprop(ctx android.ModuleContext, syspropFile android.Path) android.Path {
+	srcJarFile := android.GenPathWithExt(ctx, "sysprop", syspropFile, "srcjar")
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        sysprop,
+		Description: "sysprop_java " + syspropFile.Rel(),
+		Output:      srcJarFile,
+		Input:       syspropFile,
+	})
+
+	return srcJarFile
+}
+
 func (j *Module) genSources(ctx android.ModuleContext, srcFiles android.Paths,
 	flags javaBuilderFlags) android.Paths {
 
@@ -99,6 +124,9 @@
 		case ".proto":
 			srcJarFile := genProto(ctx, srcFile, flags)
 			outSrcFiles = append(outSrcFiles, srcJarFile)
+		case ".sysprop":
+			srcJarFile := genSysprop(ctx, srcFile)
+			outSrcFiles = append(outSrcFiles, srcJarFile)
 		default:
 			outSrcFiles = append(outSrcFiles, srcFile)
 		}
diff --git a/java/java.go b/java/java.go
index d7068c6..f651884 100644
--- a/java/java.go
+++ b/java/java.go
@@ -725,27 +725,34 @@
 	javaPlatform
 )
 
-func getLinkType(m *Module, name string) linkType {
+func getLinkType(m *Module, name string) (ret linkType, stubs bool) {
 	ver := m.sdkVersion()
-	noStdLibs := Bool(m.properties.No_standard_libs)
 	switch {
-	case name == "core.current.stubs" || ver == "core_current" ||
-		name == "core.platform.api.stubs" || ver == "core_platform_current" ||
-		noStdLibs || name == "stub-annotations" || name == "private-stub-annotations-jar":
-		return javaCore
-	case name == "android_system_stubs_current" || strings.HasPrefix(ver, "system_"):
-		return javaSystem
-	case name == "android_test_stubs_current" || strings.HasPrefix(ver, "test_"):
-		return javaPlatform
-	case name == "android_stubs_current" || ver == "current":
-		return javaSdk
+	case name == "core.current.stubs" || name == "core.platform.api.stubs" ||
+		name == "stub-annotations" || name == "private-stub-annotations-jar" ||
+		name == "core-lambda-stubs":
+		return javaCore, true
+	case ver == "core_current" || ver == "core_platform_current":
+		return javaCore, false
+	case name == "android_system_stubs_current":
+		return javaSystem, true
+	case strings.HasPrefix(ver, "system_"):
+		return javaSystem, false
+	case name == "android_test_stubs_current":
+		return javaSystem, true
+	case strings.HasPrefix(ver, "test_"):
+		return javaPlatform, false
+	case name == "android_stubs_current":
+		return javaSdk, true
+	case ver == "current":
+		return javaSdk, false
 	case ver == "":
-		return javaPlatform
+		return javaPlatform, false
 	default:
 		if _, err := strconv.Atoi(ver); err != nil {
 			panic(fmt.Errorf("expected sdk_version to be a number, got %q", ver))
 		}
-		return javaSdk
+		return javaSdk, false
 	}
 }
 
@@ -754,8 +761,11 @@
 		return
 	}
 
-	myLinkType := getLinkType(from, ctx.ModuleName())
-	otherLinkType := getLinkType(&to.Module, ctx.OtherModuleName(to))
+	myLinkType, stubs := getLinkType(from, ctx.ModuleName())
+	if stubs {
+		return
+	}
+	otherLinkType, _ := getLinkType(&to.Module, ctx.OtherModuleName(to))
 	commonMessage := "Adjust sdk_version: property of the source or target module so that target module is built with the same or smaller API set than the source."
 
 	switch myLinkType {
@@ -860,7 +870,8 @@
 		case SdkLibraryDependency:
 			switch tag {
 			case libTag:
-				deps.classpath = append(deps.classpath, dep.HeaderJars(getLinkType(j, ctx.ModuleName()))...)
+				linkType, _ := getLinkType(j, ctx.ModuleName())
+				deps.classpath = append(deps.classpath, dep.HeaderJars(linkType)...)
 				// names of sdk libs that are directly depended are exported
 				j.exportedSdkLibs = append(j.exportedSdkLibs, otherName)
 			default:
diff --git a/cmd/symbol_inject/Android.bp b/symbol_inject/Android.bp
similarity index 90%
rename from cmd/symbol_inject/Android.bp
rename to symbol_inject/Android.bp
index a2ea12b..8308043 100644
--- a/cmd/symbol_inject/Android.bp
+++ b/symbol_inject/Android.bp
@@ -12,8 +12,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-blueprint_go_binary {
-    name: "symbol_inject",
+bootstrap_go_package {
+    name: "soong-symbol_inject",
+    pkgPath: "android/soong/symbol_inject",
     srcs: [
         "symbol_inject.go",
         "elf.go",
diff --git a/cmd/symbol_inject/Android.bp b/symbol_inject/cmd/Android.bp
similarity index 71%
copy from cmd/symbol_inject/Android.bp
copy to symbol_inject/cmd/Android.bp
index a2ea12b..ee2f259 100644
--- a/cmd/symbol_inject/Android.bp
+++ b/symbol_inject/cmd/Android.bp
@@ -14,19 +14,8 @@
 
 blueprint_go_binary {
     name: "symbol_inject",
+    deps: ["soong-symbol_inject"],
     srcs: [
         "symbol_inject.go",
-        "elf.go",
-        "macho.go",
-        "pe.go",
-    ],
-    testSrcs: [
-        "elf_symboldata_test.go",
-        "elf_test.go",
-        "macho_symboldata_test.go",
-        "macho_test.go",
-        "pe_symboldata_test.go",
-        "pe_test.go",
-        "symbol_inject_test.go",
     ],
 }
diff --git a/symbol_inject/cmd/symbol_inject.go b/symbol_inject/cmd/symbol_inject.go
new file mode 100644
index 0000000..1397b37
--- /dev/null
+++ b/symbol_inject/cmd/symbol_inject.go
@@ -0,0 +1,97 @@
+// Copyright 2018 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+	"flag"
+	"fmt"
+	"os"
+
+	"android/soong/symbol_inject"
+)
+
+var (
+	input  = flag.String("i", "", "input file")
+	output = flag.String("o", "", "output file")
+	symbol = flag.String("s", "", "symbol to inject into")
+	from   = flag.String("from", "", "optional existing value of the symbol for verification")
+	value  = flag.String("v", "", "value to inject into symbol")
+
+	dump = flag.Bool("dump", false, "dump the symbol table for copying into a test")
+)
+
+func main() {
+	flag.Parse()
+
+	usageError := func(s string) {
+		fmt.Fprintln(os.Stderr, s)
+		flag.Usage()
+		os.Exit(1)
+	}
+
+	if *input == "" {
+		usageError("-i is required")
+	}
+
+	if !*dump {
+		if *output == "" {
+			usageError("-o is required")
+		}
+
+		if *symbol == "" {
+			usageError("-s is required")
+		}
+
+		if *value == "" {
+			usageError("-v is required")
+		}
+	}
+
+	r, err := os.Open(*input)
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err.Error())
+		os.Exit(2)
+	}
+	defer r.Close()
+
+	if *dump {
+		err := symbol_inject.DumpSymbols(r)
+		if err != nil {
+			fmt.Fprintln(os.Stderr, err.Error())
+			os.Exit(6)
+		}
+		return
+	}
+
+	w, err := os.OpenFile(*output, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0777)
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err.Error())
+		os.Exit(3)
+	}
+	defer w.Close()
+
+	file, err := symbol_inject.OpenFile(r)
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err.Error())
+		os.Exit(4)
+	}
+
+	err = symbol_inject.InjectStringSymbol(file, w, *symbol, *value, *from)
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err.Error())
+		os.Remove(*output)
+		os.Exit(5)
+	}
+}
diff --git a/cmd/symbol_inject/elf.go b/symbol_inject/elf.go
similarity index 99%
rename from cmd/symbol_inject/elf.go
rename to symbol_inject/elf.go
index d94877d..8742cbd 100644
--- a/cmd/symbol_inject/elf.go
+++ b/symbol_inject/elf.go
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package main
+package symbol_inject
 
 import (
 	"debug/elf"
diff --git a/cmd/symbol_inject/elf_symboldata_test.go b/symbol_inject/elf_symboldata_test.go
similarity index 99%
rename from cmd/symbol_inject/elf_symboldata_test.go
rename to symbol_inject/elf_symboldata_test.go
index 9ba7153..b2f1148 100644
--- a/cmd/symbol_inject/elf_symboldata_test.go
+++ b/symbol_inject/elf_symboldata_test.go
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package main
+package symbol_inject
 
 import "debug/elf"
 
diff --git a/cmd/symbol_inject/elf_test.go b/symbol_inject/elf_test.go
similarity index 98%
rename from cmd/symbol_inject/elf_test.go
rename to symbol_inject/elf_test.go
index 30b46a5..aceee44 100644
--- a/cmd/symbol_inject/elf_test.go
+++ b/symbol_inject/elf_test.go
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package main
+package symbol_inject
 
 import (
 	"strconv"
diff --git a/cmd/symbol_inject/macho.go b/symbol_inject/macho.go
similarity index 98%
rename from cmd/symbol_inject/macho.go
rename to symbol_inject/macho.go
index be49f8b..6ee3f4f 100644
--- a/cmd/symbol_inject/macho.go
+++ b/symbol_inject/macho.go
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package main
+package symbol_inject
 
 import (
 	"debug/macho"
diff --git a/cmd/symbol_inject/macho_symboldata_test.go b/symbol_inject/macho_symboldata_test.go
similarity index 99%
rename from cmd/symbol_inject/macho_symboldata_test.go
rename to symbol_inject/macho_symboldata_test.go
index 3100a81..7336a27 100644
--- a/cmd/symbol_inject/macho_symboldata_test.go
+++ b/symbol_inject/macho_symboldata_test.go
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package main
+package symbol_inject
 
 import (
 	"debug/macho"
diff --git a/cmd/symbol_inject/macho_test.go b/symbol_inject/macho_test.go
similarity index 98%
rename from cmd/symbol_inject/macho_test.go
rename to symbol_inject/macho_test.go
index 7acab23..50df131 100644
--- a/cmd/symbol_inject/macho_test.go
+++ b/symbol_inject/macho_test.go
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package main
+package symbol_inject
 
 import (
 	"debug/macho"
diff --git a/cmd/symbol_inject/pe.go b/symbol_inject/pe.go
similarity index 98%
rename from cmd/symbol_inject/pe.go
rename to symbol_inject/pe.go
index 12f35ee..58cf91a 100644
--- a/cmd/symbol_inject/pe.go
+++ b/symbol_inject/pe.go
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package main
+package symbol_inject
 
 import (
 	"debug/pe"
diff --git a/cmd/symbol_inject/pe_symboldata_test.go b/symbol_inject/pe_symboldata_test.go
similarity index 99%
rename from cmd/symbol_inject/pe_symboldata_test.go
rename to symbol_inject/pe_symboldata_test.go
index edc1c97..5c0fd70 100644
--- a/cmd/symbol_inject/pe_symboldata_test.go
+++ b/symbol_inject/pe_symboldata_test.go
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package main
+package symbol_inject
 
 import (
 	"debug/pe"
diff --git a/cmd/symbol_inject/pe_test.go b/symbol_inject/pe_test.go
similarity index 99%
rename from cmd/symbol_inject/pe_test.go
rename to symbol_inject/pe_test.go
index 21a0bc4..df7bac3 100644
--- a/cmd/symbol_inject/pe_test.go
+++ b/symbol_inject/pe_test.go
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package main
+package symbol_inject
 
 import (
 	"debug/pe"
diff --git a/cmd/symbol_inject/symbol_inject.go b/symbol_inject/symbol_inject.go
similarity index 70%
rename from cmd/symbol_inject/symbol_inject.go
rename to symbol_inject/symbol_inject.go
index d0f01c5..2a3d67e 100644
--- a/cmd/symbol_inject/symbol_inject.go
+++ b/symbol_inject/symbol_inject.go
@@ -12,25 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package main
+package symbol_inject
 
 import (
 	"bytes"
-	"flag"
+	"encoding/binary"
 	"fmt"
 	"io"
 	"math"
-	"os"
-)
-
-var (
-	input  = flag.String("i", "", "input file")
-	output = flag.String("o", "", "output file")
-	symbol = flag.String("s", "", "symbol to inject into")
-	from   = flag.String("from", "", "optional existing value of the symbol for verification")
-	value  = flag.String("v", "", "value to inject into symbol")
-
-	dump = flag.Bool("dump", false, "dump the symbol table for copying into a test")
 )
 
 var maxUint64 uint64 = math.MaxUint64
@@ -39,71 +28,7 @@
 	error
 }
 
-func main() {
-	flag.Parse()
-
-	usageError := func(s string) {
-		fmt.Fprintln(os.Stderr, s)
-		flag.Usage()
-		os.Exit(1)
-	}
-
-	if *input == "" {
-		usageError("-i is required")
-	}
-
-	if !*dump {
-		if *output == "" {
-			usageError("-o is required")
-		}
-
-		if *symbol == "" {
-			usageError("-s is required")
-		}
-
-		if *value == "" {
-			usageError("-v is required")
-		}
-	}
-
-	r, err := os.Open(*input)
-	if err != nil {
-		fmt.Fprintln(os.Stderr, err.Error())
-		os.Exit(2)
-	}
-	defer r.Close()
-
-	if *dump {
-		err := dumpSymbols(r)
-		if err != nil {
-			fmt.Fprintln(os.Stderr, err.Error())
-			os.Exit(6)
-		}
-		return
-	}
-
-	w, err := os.OpenFile(*output, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0777)
-	if err != nil {
-		fmt.Fprintln(os.Stderr, err.Error())
-		os.Exit(3)
-	}
-	defer w.Close()
-
-	file, err := openFile(r)
-	if err != nil {
-		fmt.Fprintln(os.Stderr, err.Error())
-		os.Exit(4)
-	}
-
-	err = injectSymbol(file, w, *symbol, *value, *from)
-	if err != nil {
-		fmt.Fprintln(os.Stderr, err.Error())
-		os.Remove(*output)
-		os.Exit(5)
-	}
-}
-
-func openFile(r io.ReaderAt) (*File, error) {
+func OpenFile(r io.ReaderAt) (*File, error) {
 	file, err := elfSymbolsFromFile(r)
 	if elfError, ok := err.(cantParseError); ok {
 		// Try as a mach-o file
@@ -126,7 +51,7 @@
 	return file, err
 }
 
-func injectSymbol(file *File, w io.Writer, symbol, value, from string) error {
+func InjectStringSymbol(file *File, w io.Writer, symbol, value, from string) error {
 	offset, size, err := findSymbol(file, symbol)
 	if err != nil {
 		return err
@@ -151,13 +76,29 @@
 		}
 	}
 
-	return copyAndInject(file.r, w, offset, size, value)
-}
-
-func copyAndInject(r io.ReaderAt, w io.Writer, offset, size uint64, value string) (err error) {
 	buf := make([]byte, size)
 	copy(buf, value)
 
+	return copyAndInject(file.r, w, offset, buf)
+}
+
+func InjectUint64Symbol(file *File, w io.Writer, symbol string, value uint64) error {
+	offset, size, err := findSymbol(file, symbol)
+	if err != nil {
+		return err
+	}
+
+	if size != 8 {
+		return fmt.Errorf("symbol %q is not a uint64, it is %d bytes long", symbol, size)
+	}
+
+	buf := make([]byte, 8)
+	binary.LittleEndian.PutUint64(buf, value)
+
+	return copyAndInject(file.r, w, offset, buf)
+}
+
+func copyAndInject(r io.ReaderAt, w io.Writer, offset uint64, buf []byte) (err error) {
 	// Copy the first bytes up to the symbol offset
 	_, err = io.Copy(w, io.NewSectionReader(r, 0, int64(offset)))
 
@@ -167,7 +108,7 @@
 	}
 
 	// Write the remainder of the file
-	pos := int64(offset + size)
+	pos := int64(offset) + int64(len(buf))
 	if err == nil {
 		_, err = io.Copy(w, io.NewSectionReader(r, pos, 1<<63-1-pos))
 	}
@@ -239,7 +180,7 @@
 	Size   uint64
 }
 
-func dumpSymbols(r io.ReaderAt) error {
+func DumpSymbols(r io.ReaderAt) error {
 	err := dumpElfSymbols(r)
 	if elfError, ok := err.(cantParseError); ok {
 		// Try as a mach-o file
diff --git a/cmd/symbol_inject/symbol_inject_test.go b/symbol_inject/symbol_inject_test.go
similarity index 77%
rename from cmd/symbol_inject/symbol_inject_test.go
rename to symbol_inject/symbol_inject_test.go
index dbee39a..6607e65 100644
--- a/cmd/symbol_inject/symbol_inject_test.go
+++ b/symbol_inject/symbol_inject_test.go
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package main
+package symbol_inject
 
 import (
 	"bytes"
@@ -23,32 +23,23 @@
 func TestCopyAndInject(t *testing.T) {
 	s := "abcdefghijklmnopqrstuvwxyz"
 	testCases := []struct {
-		offset, size uint64
-		value        string
-		expected     string
+		offset   uint64
+		buf      string
+		expected string
 	}{
 		{
 			offset:   0,
-			size:     1,
-			value:    "A",
+			buf:      "A",
 			expected: "Abcdefghijklmnopqrstuvwxyz",
 		},
 		{
 			offset:   1,
-			size:     1,
-			value:    "B",
-			expected: "aBcdefghijklmnopqrstuvwxyz",
-		},
-		{
-			offset:   1,
-			size:     1,
-			value:    "BCD",
+			buf:      "B",
 			expected: "aBcdefghijklmnopqrstuvwxyz",
 		},
 		{
 			offset:   25,
-			size:     1,
-			value:    "Z",
+			buf:      "Z",
 			expected: "abcdefghijklmnopqrstuvwxyZ",
 		},
 	}
@@ -57,7 +48,7 @@
 		t.Run(strconv.Itoa(i), func(t *testing.T) {
 			in := bytes.NewReader([]byte(s))
 			out := &bytes.Buffer{}
-			copyAndInject(in, out, testCase.offset, testCase.size, testCase.value)
+			copyAndInject(in, out, testCase.offset, []byte(testCase.buf))
 
 			if out.String() != testCase.expected {
 				t.Errorf("expected %s, got %s", testCase.expected, out.String())
diff --git a/tradefed/autogen.go b/tradefed/autogen.go
index 131fdc4..5fb85c3 100644
--- a/tradefed/autogen.go
+++ b/tradefed/autogen.go
@@ -15,6 +15,7 @@
 package tradefed
 
 import (
+	"fmt"
 	"strings"
 
 	"github.com/google/blueprint"
@@ -36,9 +37,10 @@
 }
 
 var autogenTestConfig = pctx.StaticRule("autogenTestConfig", blueprint.RuleParams{
-	Command:     "sed 's&{MODULE}&${name}&g' $template > $out",
+	Command: "sed 's&{MODULE}&${name}&g' $template > $out &&" +
+		"${optionCmd} $out",
 	CommandDeps: []string{"$template"},
-}, "name", "template")
+}, "name", "template", "optionCmd")
 
 func testConfigPath(ctx android.ModuleContext, prop *string) (path android.Path, autogenPath android.WritablePath) {
 	if p := getTestConfig(ctx, prop); p != nil {
@@ -54,30 +56,44 @@
 	}
 }
 
-func autogenTemplate(ctx android.ModuleContext, output android.WritablePath, template string) {
+func autogenTemplate(ctx android.ModuleContext, output android.WritablePath, template string, optionsMap map[string]string) {
+	// If no test option found, delete {UID_OPTION} line.
+	// If found, replace it with corresponding options format.
+	optionCmd := "sed -i '/{UID_OPTION}/d'"
+	if optionsMap != nil {
+		//Append options
+		var options []string
+		for optionName, value := range optionsMap {
+			if value != "" {
+				options = append(options, fmt.Sprintf("<option name=\"%s\" value=\"%s\" />", optionName, value))
+			}
+		}
+		optionCmd = fmt.Sprintf("sed -i 's&{UID_OPTION}&%s&g'", strings.Join(options, "\\n        "))
+	}
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        autogenTestConfig,
 		Description: "test config",
 		Output:      output,
 		Args: map[string]string{
-			"name":     ctx.ModuleName(),
-			"template": template,
+			"name":      ctx.ModuleName(),
+			"template":  template,
+			"optionCmd": optionCmd,
 		},
 	})
 }
 
 func AutoGenNativeTestConfig(ctx android.ModuleContext, testConfigProp *string,
-	testConfigTemplateProp *string) android.Path {
+	testConfigTemplateProp *string, optionsMap map[string]string) android.Path {
 	path, autogenPath := testConfigPath(ctx, testConfigProp)
 	if autogenPath != nil {
 		templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
 		if templatePath.Valid() {
-			autogenTemplate(ctx, autogenPath, templatePath.String())
+			autogenTemplate(ctx, autogenPath, templatePath.String(), optionsMap)
 		} else {
 			if ctx.Device() {
-				autogenTemplate(ctx, autogenPath, "${NativeTestConfigTemplate}")
+				autogenTemplate(ctx, autogenPath, "${NativeTestConfigTemplate}", optionsMap)
 			} else {
-				autogenTemplate(ctx, autogenPath, "${NativeHostTestConfigTemplate}")
+				autogenTemplate(ctx, autogenPath, "${NativeHostTestConfigTemplate}", optionsMap)
 			}
 		}
 		return autogenPath
@@ -91,9 +107,9 @@
 	if autogenPath != nil {
 		templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
 		if templatePath.Valid() {
-			autogenTemplate(ctx, autogenPath, templatePath.String())
+			autogenTemplate(ctx, autogenPath, templatePath.String(), nil)
 		} else {
-			autogenTemplate(ctx, autogenPath, "${NativeBenchmarkTestConfigTemplate}")
+			autogenTemplate(ctx, autogenPath, "${NativeBenchmarkTestConfigTemplate}", nil)
 		}
 		return autogenPath
 	}
@@ -105,12 +121,12 @@
 	if autogenPath != nil {
 		templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
 		if templatePath.Valid() {
-			autogenTemplate(ctx, autogenPath, templatePath.String())
+			autogenTemplate(ctx, autogenPath, templatePath.String(), nil)
 		} else {
 			if ctx.Device() {
-				autogenTemplate(ctx, autogenPath, "${JavaTestConfigTemplate}")
+				autogenTemplate(ctx, autogenPath, "${JavaTestConfigTemplate}", nil)
 			} else {
-				autogenTemplate(ctx, autogenPath, "${JavaHostTestConfigTemplate}")
+				autogenTemplate(ctx, autogenPath, "${JavaHostTestConfigTemplate}", nil)
 			}
 		}
 		return autogenPath
diff --git a/ui/build/build.go b/ui/build/build.go
index 377481b..c902a0f 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -40,9 +40,10 @@
 pool local_pool
  depth = {{.Parallel}}
 build _kati_always_build_: phony
-{{if .HasKatiSuffix}}include {{.KatiBuildNinjaFile}}
+{{if .HasKatiSuffix}}subninja {{.KatiBuildNinjaFile}}
+subninja {{.KatiPackageNinjaFile}}
 {{end -}}
-include {{.SoongNinjaFile}}
+subninja {{.SoongNinjaFile}}
 `))
 
 func createCombinedBuildNinjaFile(ctx Context, config Config) {
@@ -180,6 +181,7 @@
 		genKatiSuffix(ctx, config)
 		runKatiCleanSpec(ctx, config)
 		runKatiBuild(ctx, config)
+		runKatiPackage(ctx, config)
 
 		ioutil.WriteFile(config.LastKatiSuffixFile(), []byte(config.KatiSuffix()), 0777)
 	} else {
diff --git a/ui/build/config.go b/ui/build/config.go
index d65d97f..840f505 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -34,6 +34,7 @@
 	arguments []string
 	goma      bool
 	environ   *Environment
+	distDir   string
 
 	// From the arguments
 	parallel   int
@@ -86,8 +87,11 @@
 		ret.environ.Set("OUT_DIR", outDir)
 	}
 
-	// Make sure DIST_DIR is set appropriately
-	ret.environ.Set("DIST_DIR", ret.DistDir())
+	if distDir, ok := ret.environ.Get("DIST_DIR"); ok {
+		ret.distDir = filepath.Clean(distDir)
+	} else {
+		ret.distDir = filepath.Join(ret.OutDir(), "dist")
+	}
 
 	ret.environ.Unset(
 		// We're already using it
@@ -110,6 +114,9 @@
 		// We handle this above
 		"OUT_DIR_COMMON_BASE",
 
+		// This is handled above too, and set for individual commands later
+		"DIST_DIR",
+
 		// Variables that have caused problems in the past
 		"CDPATH",
 		"DISPLAY",
@@ -251,10 +258,10 @@
 			}
 		} else if k, v, ok := decodeKeyValue(arg); ok && len(k) > 0 {
 			c.environ.Set(k, v)
+		} else if arg == "dist" {
+			c.dist = true
 		} else {
-			if arg == "dist" {
-				c.dist = true
-			} else if arg == "checkbuild" {
+			if arg == "checkbuild" {
 				c.checkbuild = true
 			}
 			c.arguments = append(c.arguments, arg)
@@ -378,10 +385,7 @@
 }
 
 func (c *configImpl) DistDir() string {
-	if distDir, ok := c.environ.Get("DIST_DIR"); ok {
-		return filepath.Clean(distDir)
-	}
-	return filepath.Join(c.OutDir(), "dist")
+	return c.distDir
 }
 
 func (c *configImpl) NinjaArgs() []string {
@@ -508,6 +512,10 @@
 	return filepath.Join(c.OutDir(), "build"+c.KatiSuffix()+katiBuildSuffix+".ninja")
 }
 
+func (c *configImpl) KatiPackageNinjaFile() string {
+	return filepath.Join(c.OutDir(), "build"+c.KatiSuffix()+katiPackageSuffix+".ninja")
+}
+
 func (c *configImpl) SoongNinjaFile() string {
 	return filepath.Join(c.SoongOutDir(), "build.ninja")
 }
@@ -535,6 +543,10 @@
 	return filepath.Join(c.ProductOut(), "previous_build_config.mk")
 }
 
+func (c *configImpl) KatiPackageMkDir() string {
+	return filepath.Join(c.ProductOut(), "obj", "CONFIG", "kati_packaging")
+}
+
 func (c *configImpl) hostOutRoot() string {
 	return filepath.Join(c.OutDir(), "host")
 }
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index ffea841..ad57d02 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -32,8 +32,40 @@
 //
 // vars is the list of variables to read. The values will be put in the
 // returned map.
+//
+// variables controlled by soong_ui directly are now returned without needing
+// to call into make, to retain compatibility.
 func DumpMakeVars(ctx Context, config Config, goals, vars []string) (map[string]string, error) {
-	return dumpMakeVars(ctx, config, goals, vars, false)
+	soongUiVars := map[string]func() string{
+		"OUT_DIR":  func() string { return config.OutDir() },
+		"DIST_DIR": func() string { return config.DistDir() },
+	}
+
+	makeVars := make([]string, 0, len(vars))
+	for _, v := range vars {
+		if _, ok := soongUiVars[v]; !ok {
+			makeVars = append(makeVars, v)
+		}
+	}
+
+	var ret map[string]string
+	if len(makeVars) > 0 {
+		var err error
+		ret, err = dumpMakeVars(ctx, config, goals, makeVars, false)
+		if err != nil {
+			return ret, err
+		}
+	} else {
+		ret = make(map[string]string)
+	}
+
+	for _, v := range vars {
+		if f, ok := soongUiVars[v]; ok {
+			ret[v] = f()
+		}
+	}
+
+	return ret, nil
 }
 
 func dumpMakeVars(ctx Context, config Config, goals, vars []string, write_soong_vars bool) (map[string]string, error) {
@@ -48,7 +80,6 @@
 		"dump-many-vars",
 		"MAKECMDGOALS="+strings.Join(goals, " "))
 	cmd.Environment.Set("CALLED_FROM_SETUP", "true")
-	cmd.Environment.Set("BUILD_SYSTEM", "build/make/core")
 	if write_soong_vars {
 		cmd.Environment.Set("WRITE_SOONG_VARIABLES", "true")
 	}
diff --git a/ui/build/environment.go b/ui/build/environment.go
index cbeeb4b..d8ff7f2 100644
--- a/ui/build/environment.go
+++ b/ui/build/environment.go
@@ -75,6 +75,17 @@
 	*e = out
 }
 
+// Allow removes all keys that are not present in the input list
+func (e *Environment) Allow(keys ...string) {
+	out := (*e)[:0]
+	for _, env := range *e {
+		if key, _, ok := decodeKeyValue(env); ok && inList(key, keys) {
+			out = append(out, env)
+		}
+	}
+	*e = out
+}
+
 // Environ returns the []string required for exec.Cmd.Env
 func (e *Environment) Environ() []string {
 	return []string(*e)
diff --git a/ui/build/environment_test.go b/ui/build/environment_test.go
index 0294dac..37f500f 100644
--- a/ui/build/environment_test.go
+++ b/ui/build/environment_test.go
@@ -56,6 +56,15 @@
 	}
 }
 
+func TestEnvAllow(t *testing.T) {
+	initial := &Environment{"TEST=1", "TEST2=0", "TEST3=2"}
+	initial.Allow("TEST3", "TEST")
+	got := initial.Environ()
+	if len(got) != 2 || got[0] != "TEST=1" || got[1] != "TEST3=2" {
+		t.Errorf("Expected [TEST=1 TEST3=2], got: %v", got)
+	}
+}
+
 const testKatiEnvFileContents = `#!/bin/sh
 # Generated by kati unknown
 
diff --git a/ui/build/kati.go b/ui/build/kati.go
index 546fd1a..56e9a88 100644
--- a/ui/build/kati.go
+++ b/ui/build/kati.go
@@ -28,6 +28,7 @@
 
 const katiBuildSuffix = ""
 const katiCleanspecSuffix = "-cleanspec"
+const katiPackageSuffix = "-package"
 
 // genKatiSuffix creates a suffix for kati-generated files so that we can cache
 // them based on their inputs. So this should encode all common changes to Kati
@@ -59,7 +60,7 @@
 	}
 }
 
-func runKati(ctx Context, config Config, extraSuffix string, args []string) {
+func runKati(ctx Context, config Config, extraSuffix string, args []string, envFunc func(*Environment)) {
 	executable := config.PrebuiltBuildTool("ckati")
 	args = append([]string{
 		"--ninja",
@@ -80,10 +81,6 @@
 		"--kati_stats",
 	}, args...)
 
-	args = append(args,
-		"SOONG_MAKEVARS_MK="+config.SoongMakeVarsMk(),
-		"TARGET_DEVICE_DIR="+config.TargetDeviceDir())
-
 	cmd := Command(ctx, config, "ckati", executable, args...)
 	cmd.Sandbox = katiSandbox
 	pipe, err := cmd.StdoutPipe()
@@ -92,6 +89,8 @@
 	}
 	cmd.Stderr = cmd.Stdout
 
+	envFunc(cmd.Environment)
+
 	cmd.StartOrFatal()
 	status.KatiReader(ctx.Status.StartTool(), pipe)
 	cmd.WaitOrFatal()
@@ -103,7 +102,6 @@
 
 	args := []string{
 		"--writable", config.OutDir() + "/",
-		"--writable", config.DistDir() + "/",
 		"-f", "build/make/core/main.mk",
 	}
 
@@ -125,9 +123,54 @@
 
 	args = append(args, config.KatiArgs()...)
 
-	args = append(args, "SOONG_ANDROID_MK="+config.SoongAndroidMk())
+	args = append(args,
+		"SOONG_MAKEVARS_MK="+config.SoongMakeVarsMk(),
+		"SOONG_ANDROID_MK="+config.SoongAndroidMk(),
+		"TARGET_DEVICE_DIR="+config.TargetDeviceDir(),
+		"KATI_PACKAGE_MK_DIR="+config.KatiPackageMkDir())
 
-	runKati(ctx, config, katiBuildSuffix, args)
+	runKati(ctx, config, katiBuildSuffix, args, func(env *Environment) {})
+}
+
+func runKatiPackage(ctx Context, config Config) {
+	ctx.BeginTrace("kati package")
+	defer ctx.EndTrace()
+
+	args := []string{
+		"--writable", config.DistDir() + "/",
+		"--werror_writable",
+		"--werror_implicit_rules",
+		"--werror_overriding_commands",
+		"--werror_real_to_phony",
+		"--werror_phony_looks_real",
+		"-f", "build/make/packaging/main.mk",
+		"KATI_PACKAGE_MK_DIR=" + config.KatiPackageMkDir(),
+	}
+
+	runKati(ctx, config, katiPackageSuffix, args, func(env *Environment) {
+		env.Allow([]string{
+			// Some generic basics
+			"LANG",
+			"LC_MESSAGES",
+			"PATH",
+			"PWD",
+			"TMPDIR",
+
+			// Tool configs
+			"JAVA_HOME",
+			"PYTHONDONTWRITEBYTECODE",
+
+			// Build configuration
+			"ANDROID_BUILD_SHELL",
+			"DIST_DIR",
+			"OUT_DIR",
+		}...)
+
+		if config.Dist() {
+			env.Set("DIST", "true")
+			env.Set("DIST_DIR", config.DistDir())
+		}
+	})
 }
 
 func runKatiCleanSpec(ctx Context, config Config) {
@@ -138,5 +181,7 @@
 		"--werror_implicit_rules",
 		"--werror_overriding_commands",
 		"-f", "build/make/core/cleanbuild.mk",
-	})
+		"SOONG_MAKEVARS_MK=" + config.SoongMakeVarsMk(),
+		"TARGET_DEVICE_DIR=" + config.TargetDeviceDir(),
+	}, func(env *Environment) {})
 }
diff --git a/ui/build/ninja.go b/ui/build/ninja.go
index 91cb475..c8f19d1 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -60,6 +60,8 @@
 		cmd.Environment.AppendFromKati(config.KatiEnvFile())
 	}
 
+	cmd.Environment.Set("DIST_DIR", config.DistDir())
+
 	// Allow both NINJA_ARGS and NINJA_EXTRA_ARGS, since both have been
 	// used in the past to specify extra ninja arguments.
 	if extra, ok := cmd.Environment.Get("NINJA_ARGS"); ok {
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index 7e19da6..c4fcc20 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -101,7 +101,6 @@
 	"ls":        Allowed,
 	"lsof":      Allowed,
 	"m4":        Allowed,
-	"make":      Log,
 	"md5sum":    Allowed,
 	"mkdir":     Allowed,
 	"mktemp":    Allowed,
@@ -148,7 +147,6 @@
 	"which":     Allowed,
 	"whoami":    Allowed,
 	"xargs":     Allowed,
-	"xmllint":   Log,
 	"xxd":       Allowed,
 	"xz":        Allowed,
 	"zip":       Allowed,
diff --git a/ui/status/kati.go b/ui/status/kati.go
index 552a9e9..7c26d42 100644
--- a/ui/status/kati.go
+++ b/ui/status/kati.go
@@ -24,7 +24,7 @@
 )
 
 var katiError = regexp.MustCompile(`^(\033\[1m)?[^ ]+:[0-9]+: (\033\[31m)?error:`)
-var katiIncludeRe = regexp.MustCompile(`^(\[(\d+)/(\d+)] )?((including [^ ]+|initializing build system|finishing build rules|writing build rules) ...)$`)
+var katiIncludeRe = regexp.MustCompile(`^(\[(\d+)/(\d+)] )?((including [^ ]+|initializing (build|packaging) system|finishing (build|packaging) rules|writing (build|packaging) rules) ...)$`)
 var katiLogRe = regexp.MustCompile(`^\*kati\*: `)
 var katiNinjaMissing = regexp.MustCompile("^[^ ]+ is missing, regenerating...$")