Merge "Update Soong docs generator for blueprint changes"
diff --git a/Android.bp b/Android.bp
index 92a6e9d..b407314 100644
--- a/Android.bp
+++ b/Android.bp
@@ -148,6 +148,7 @@
         "cc/sabi.go",
         "cc/stl.go",
         "cc/strip.go",
+        "cc/sysprop.go",
         "cc/tidy.go",
         "cc/util.go",
         "cc/vndk.go",
@@ -178,6 +179,8 @@
         "cc/genrule.go",
 
         "cc/vendor_public_library.go",
+
+        "cc/testing.go",
     ],
     testSrcs: [
         "cc/cc_test.go",
@@ -378,6 +381,25 @@
     pluginFor: ["soong_build"],
 }
 
+bootstrap_go_package {
+    name: "soong-sysprop",
+    pkgPath: "android/soong/sysprop",
+    deps: [
+        "blueprint",
+        "soong",
+        "soong-android",
+        "soong-cc",
+        "soong-java",
+    ],
+    srcs: [
+        "sysprop/sysprop_library.go",
+    ],
+    testSrcs: [
+        "sysprop/sysprop_test.go",
+    ],
+    pluginFor: ["soong_build"],
+}
+
 //
 // Defaults to enable various configurations of host bionic
 //
diff --git a/android/hooks.go b/android/hooks.go
index 57560d2..6b2468d 100644
--- a/android/hooks.go
+++ b/android/hooks.go
@@ -123,7 +123,7 @@
 	install []func(InstallHookContext)
 }
 
-func loadHookMutator(ctx TopDownMutatorContext) {
+func LoadHookMutator(ctx TopDownMutatorContext) {
 	if m, ok := ctx.Module().(Module); ok {
 		// Cast through *androidTopDownMutatorContext because AppendProperties is implemented
 		// on *androidTopDownMutatorContext but not exposed through TopDownMutatorContext
diff --git a/android/mutator.go b/android/mutator.go
index b77c2f0..e5f742f 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -74,7 +74,7 @@
 
 var preArch = []RegisterMutatorFunc{
 	func(ctx RegisterMutatorsContext) {
-		ctx.TopDown("load_hooks", loadHookMutator).Parallel()
+		ctx.TopDown("load_hooks", LoadHookMutator).Parallel()
 	},
 	RegisterNamespaceMutator,
 	RegisterPrebuiltsPreArchMutators,
diff --git a/android/rule_builder.go b/android/rule_builder.go
index 468b617..3b86947 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -28,7 +28,7 @@
 // graph.
 type RuleBuilder struct {
 	commands       []*RuleBuilderCommand
-	installs       []RuleBuilderInstall
+	installs       RuleBuilderInstalls
 	temporariesSet map[string]bool
 	restat         bool
 	missingDeps    []string
@@ -46,6 +46,23 @@
 	From, To string
 }
 
+type RuleBuilderInstalls []RuleBuilderInstall
+
+// String returns the RuleBuilderInstalls in the form used by $(call copy-many-files) in Make, a space separated
+// list of from:to tuples.
+func (installs RuleBuilderInstalls) String() string {
+	sb := strings.Builder{}
+	for i, install := range installs {
+		if i != 0 {
+			sb.WriteRune(' ')
+		}
+		sb.WriteString(install.From)
+		sb.WriteRune(':')
+		sb.WriteString(install.To)
+	}
+	return sb.String()
+}
+
 // MissingDeps adds modules to the list of missing dependencies.  If MissingDeps
 // is called with a non-empty input, any call to Build will result in a rule
 // that will print an error listing the missing dependencies and fail.
@@ -145,8 +162,8 @@
 }
 
 // Installs returns the list of tuples passed to Install.
-func (r *RuleBuilder) Installs() []RuleBuilderInstall {
-	return append([]RuleBuilderInstall(nil), r.installs...)
+func (r *RuleBuilder) Installs() RuleBuilderInstalls {
+	return append(RuleBuilderInstalls(nil), r.installs...)
 }
 
 func (r *RuleBuilder) toolsSet() map[string]bool {
diff --git a/android/rule_builder_test.go b/android/rule_builder_test.go
index 53a5b48..f947348 100644
--- a/android/rule_builder_test.go
+++ b/android/rule_builder_test.go
@@ -84,6 +84,19 @@
 	// outputs: ["c"]
 }
 
+func ExampleRuleBuilder_Installs() {
+	rule := NewRuleBuilder()
+
+	rule.Command().Tool("ld").Inputs([]string{"a.o", "b.o"}).FlagWithOutput("-o ", "linked")
+	rule.Install("linked", "/bin/linked")
+	rule.Install("linked", "/sbin/linked")
+
+	fmt.Printf("rule.Installs().String() = %q\n", rule.Installs().String())
+
+	// Output:
+	// rule.Installs().String() = "linked:/bin/linked linked:/sbin/linked"
+}
+
 func ExampleRuleBuilderCommand() {
 	rule := NewRuleBuilder()
 
diff --git a/apex/apex.go b/apex/apex.go
index e7f498a..5e1a943 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1029,7 +1029,7 @@
 		}}
 }
 
-func (a *apexBundle) androidMkForFiles(w io.Writer, name, moduleDir string) []string {
+func (a *apexBundle) androidMkForFiles(w io.Writer, name, moduleDir string, apexType apexPackaging) []string {
 	moduleNames := []string{}
 
 	for _, fi := range a.filesInfo {
@@ -1042,7 +1042,7 @@
 		fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
 		fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
 		fmt.Fprintln(w, "LOCAL_MODULE :=", fi.moduleName)
-		if a.flattened {
+		if a.flattened && apexType.image() {
 			// /system/apex/<name>/{lib|framework|...}
 			fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(OUT_DIR)",
 				a.installDir.RelPathString(), name, fi.installDir))
@@ -1111,7 +1111,7 @@
 		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
 			moduleNames := []string{}
 			if a.installable() {
-				moduleNames = a.androidMkForFiles(w, name, moduleDir)
+				moduleNames = a.androidMkForFiles(w, name, moduleDir, apexType)
 			}
 
 			if a.flattened && apexType.image() {
diff --git a/cc/cc.go b/cc/cc.go
index 01577bc..7b19e98 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -41,6 +41,7 @@
 		ctx.BottomUp("test_per_src", testPerSrcMutator).Parallel()
 		ctx.BottomUp("version", VersionMutator).Parallel()
 		ctx.BottomUp("begin", BeginMutator).Parallel()
+		ctx.BottomUp("sysprop", SyspropMutator).Parallel()
 	})
 
 	android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
@@ -62,7 +63,7 @@
 		ctx.TopDown("sanitize_runtime_deps", sanitizerRuntimeDepsMutator)
 		ctx.BottomUp("sanitize_runtime", sanitizerRuntimeMutator).Parallel()
 
-		ctx.BottomUp("coverage", coverageLinkingMutator).Parallel()
+		ctx.BottomUp("coverage", coverageMutator).Parallel()
 		ctx.TopDown("vndk_deps", sabiDepsMutator)
 
 		ctx.TopDown("lto_deps", ltoDepsMutator)
@@ -257,6 +258,7 @@
 	baseModuleName() string
 	getVndkExtendsModuleName() string
 	isPgoCompile() bool
+	isNDKStubLibrary() bool
 	useClangLld(actx ModuleContext) bool
 	apexName() string
 	hasStubsVariants() bool
@@ -496,6 +498,10 @@
 	return c.Properties.UseVndk
 }
 
+func (c *Module) isCoverageVariant() bool {
+	return c.coverage.Properties.IsCoverageVariant
+}
+
 func (c *Module) isNdk() bool {
 	return inList(c.Name(), ndkMigratedLibs)
 }
@@ -529,6 +535,13 @@
 	return false
 }
 
+func (c *Module) isNDKStubLibrary() bool {
+	if _, ok := c.compiler.(*stubDecorator); ok {
+		return true
+	}
+	return false
+}
+
 func (c *Module) isVndkSp() bool {
 	if vndkdep := c.vndkdep; vndkdep != nil {
 		return vndkdep.isVndkSp()
@@ -674,6 +687,10 @@
 	return ctx.mod.isPgoCompile()
 }
 
+func (ctx *moduleContextImpl) isNDKStubLibrary() bool {
+	return ctx.mod.isNDKStubLibrary()
+}
+
 func (ctx *moduleContextImpl) isVndkSp() bool {
 	return ctx.mod.isVndkSp()
 }
@@ -955,7 +972,8 @@
 		// module is marked with 'bootstrap: true').
 		if c.HasStubsVariants() &&
 			android.DirectlyInAnyApex(ctx, ctx.baseModuleName()) &&
-			!c.inRecovery() && !c.useVndk() && !c.static() && c.IsStubs() {
+			!c.inRecovery() && !c.useVndk() && !c.static() && !c.isCoverageVariant() &&
+			c.IsStubs() {
 			c.Properties.HideFromMake = false // unhide
 			// Note: this is still non-installable
 		}
@@ -1211,11 +1229,18 @@
 		{Mutator: "link", Variation: "static"},
 	}, wholeStaticDepTag, deps.WholeStaticLibs...)
 
+	syspropImplLibraries := syspropImplLibraries(actx.Config())
+
 	for _, lib := range deps.StaticLibs {
 		depTag := staticDepTag
 		if inList(lib, deps.ReexportStaticLibHeaders) {
 			depTag = staticExportDepTag
 		}
+
+		if impl, ok := syspropImplLibraries[lib]; ok {
+			lib = impl
+		}
+
 		actx.AddVariationDependencies([]blueprint.Variation{
 			{Mutator: "link", Variation: "static"},
 		}, depTag, lib)
@@ -1253,12 +1278,18 @@
 	var sharedLibNames []string
 
 	for _, lib := range deps.SharedLibs {
-		name, version := stubsLibNameAndVersion(lib)
-		sharedLibNames = append(sharedLibNames, name)
 		depTag := sharedDepTag
 		if inList(lib, deps.ReexportSharedLibHeaders) {
 			depTag = sharedExportDepTag
 		}
+
+		if impl, ok := syspropImplLibraries[lib]; ok {
+			lib = impl
+		}
+
+		name, version := stubsLibNameAndVersion(lib)
+		sharedLibNames = append(sharedLibNames, name)
+
 		addSharedLibDependencies(depTag, name, version)
 	}
 
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 9d370c1..22ac0d9 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -51,165 +51,6 @@
 	os.Exit(run())
 }
 
-func gatherRequiredDeps(os android.OsType) string {
-	ret := `
-		toolchain_library {
-			name: "libatomic",
-			vendor_available: true,
-			recovery_available: true,
-			src: "",
-		}
-
-		toolchain_library {
-			name: "libcompiler_rt-extras",
-			vendor_available: true,
-			recovery_available: true,
-			src: "",
-		}
-
-		toolchain_library {
-			name: "libclang_rt.builtins-arm-android",
-			vendor_available: true,
-			recovery_available: true,
-			src: "",
-		}
-
-		toolchain_library {
-			name: "libclang_rt.builtins-aarch64-android",
-			vendor_available: true,
-			recovery_available: true,
-			src: "",
-		}
-
-		toolchain_library {
-			name: "libclang_rt.builtins-i686-android",
-			vendor_available: true,
-			recovery_available: true,
-			src: "",
-		}
-
-		toolchain_library {
-			name: "libclang_rt.builtins-x86_64-android",
-			vendor_available: true,
-			recovery_available: true,
-			src: "",
-		}
-
-		toolchain_library {
-			name: "libgcc",
-			vendor_available: true,
-			recovery_available: true,
-			src: "",
-		}
-
-		cc_library {
-			name: "libc",
-			no_libgcc: true,
-			nocrt: true,
-			system_shared_libs: [],
-			recovery_available: true,
-		}
-		llndk_library {
-			name: "libc",
-			symbol_file: "",
-		}
-		cc_library {
-			name: "libm",
-			no_libgcc: true,
-			nocrt: true,
-			system_shared_libs: [],
-			recovery_available: true,
-		}
-		llndk_library {
-			name: "libm",
-			symbol_file: "",
-		}
-		cc_library {
-			name: "libdl",
-			no_libgcc: true,
-			nocrt: true,
-			system_shared_libs: [],
-			recovery_available: true,
-		}
-		llndk_library {
-			name: "libdl",
-			symbol_file: "",
-		}
-		cc_library {
-			name: "libc++_static",
-			no_libgcc: true,
-			nocrt: true,
-			system_shared_libs: [],
-			stl: "none",
-			vendor_available: true,
-			recovery_available: true,
-		}
-		cc_library {
-			name: "libc++",
-			no_libgcc: true,
-			nocrt: true,
-			system_shared_libs: [],
-			stl: "none",
-			vendor_available: true,
-			recovery_available: true,
-			vndk: {
-				enabled: true,
-				support_system_process: true,
-			},
-		}
-		cc_library {
-			name: "libunwind_llvm",
-			no_libgcc: true,
-			nocrt: true,
-			system_shared_libs: [],
-			stl: "none",
-			vendor_available: true,
-			recovery_available: true,
-		}
-
-		cc_object {
-			name: "crtbegin_so",
-			recovery_available: true,
-			vendor_available: true,
-		}
-
-		cc_object {
-			name: "crtbegin_static",
-			recovery_available: true,
-			vendor_available: true,
-		}
-
-		cc_object {
-			name: "crtend_so",
-			recovery_available: true,
-			vendor_available: true,
-		}
-
-		cc_object {
-			name: "crtend_android",
-			recovery_available: true,
-			vendor_available: true,
-		}
-
-		cc_library {
-			name: "libprotobuf-cpp-lite",
-		}
-		`
-	if os == android.Fuchsia {
-		ret += `
-		cc_library {
-			name: "libbioniccompat",
-			stl: "none",
-		}
-		cc_library {
-			name: "libcompiler_rt",
-			stl: "none",
-		}
-		`
-	}
-	return ret
-}
-
 func createTestContext(t *testing.T, config android.Config, bp string, os android.OsType) *android.TestContext {
 	ctx := android.NewTestArchContext()
 	ctx.RegisterModuleType("cc_binary", android.ModuleFactoryAdaptor(BinaryFactory))
@@ -233,7 +74,7 @@
 	ctx.Register()
 
 	// add some modules that are required by the compiler and/or linker
-	bp = bp + gatherRequiredDeps(os)
+	bp = bp + GatherRequiredDepsForTest(os)
 
 	ctx.MockFileSystem(map[string][]byte{
 		"Android.bp":  []byte(bp),
diff --git a/cc/coverage.go b/cc/coverage.go
index 391b118..79f7d7d 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -15,13 +15,16 @@
 package cc
 
 import (
+	"strconv"
+
 	"android/soong/android"
 )
 
 type CoverageProperties struct {
 	Native_coverage *bool
 
-	CoverageEnabled bool `blueprint:"mutated"`
+	CoverageEnabled   bool `blueprint:"mutated"`
+	IsCoverageVariant bool `blueprint:"mutated"`
 }
 
 type coverage struct {
@@ -93,27 +96,54 @@
 	return flags
 }
 
-func coverageLinkingMutator(mctx android.BottomUpMutatorContext) {
-	if c, ok := mctx.Module().(*Module); ok && c.coverage != nil {
-		var enabled bool
+func coverageMutator(mctx android.BottomUpMutatorContext) {
+	// Coverage is disabled globally
+	if !mctx.DeviceConfig().NativeCoverageEnabled() {
+		return
+	}
 
-		if !mctx.DeviceConfig().NativeCoverageEnabled() {
-			// Coverage is disabled globally
-		} else if mctx.Host() {
+	if c, ok := mctx.Module().(*Module); ok {
+		var needCoverageVariant bool
+		var needCoverageBuild bool
+
+		if mctx.Host() {
 			// TODO(dwillemsen): because of -nodefaultlibs, we must depend on libclang_rt.profile-*.a
 			// Just turn off for now.
-		} else if c.coverage.Properties.Native_coverage != nil {
-			enabled = *c.coverage.Properties.Native_coverage
-		} else {
-			enabled = mctx.DeviceConfig().CoverageEnabledForPath(mctx.ModuleDir())
+		} else if c.useVndk() || c.hasVendorVariant() {
+			// Do not enable coverage for VNDK libraries
+		} else if c.isNDKStubLibrary() {
+			// Do not enable coverage for NDK stub libraries
+		} else if c.coverage != nil {
+			// Check if Native_coverage is set to false.  This property defaults to true.
+			needCoverageVariant = BoolDefault(c.coverage.Properties.Native_coverage, true)
+
+			if sdk_version := String(c.Properties.Sdk_version); sdk_version != "current" {
+				// Native coverage is not supported for SDK versions < 23
+				if fromApi, err := strconv.Atoi(sdk_version); err == nil && fromApi < 23 {
+					needCoverageVariant = false
+				}
+			}
+
+			if needCoverageVariant {
+				// Coverage variant is actually built with coverage if enabled for its module path
+				needCoverageBuild = mctx.DeviceConfig().CoverageEnabledForPath(mctx.ModuleDir())
+			}
 		}
 
-		if enabled {
-			// Create a variation so that we don't need to recompile objects
-			// when turning on or off coverage. We'll still relink the necessary
-			// binaries, since we don't know which ones those are until later.
-			m := mctx.CreateLocalVariations("cov")
-			m[0].(*Module).coverage.Properties.CoverageEnabled = true
+		if needCoverageVariant {
+			m := mctx.CreateVariations("", "cov")
+
+			// Setup the non-coverage version and set HideFromMake and
+			// PreventInstall to true.
+			m[0].(*Module).coverage.Properties.CoverageEnabled = false
+			m[0].(*Module).coverage.Properties.IsCoverageVariant = false
+			m[0].(*Module).Properties.HideFromMake = true
+			m[0].(*Module).Properties.PreventInstall = true
+
+			// The coverage-enabled version inherits HideFromMake,
+			// PreventInstall from the original module.
+			m[1].(*Module).coverage.Properties.CoverageEnabled = needCoverageBuild
+			m[1].(*Module).coverage.Properties.IsCoverageVariant = true
 		}
 	}
 }
diff --git a/cc/gen.go b/cc/gen.go
index c3088f4..0c3d089 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -56,10 +56,11 @@
 
 	sysprop = pctx.AndroidStaticRule("sysprop",
 		blueprint.RuleParams{
-			Command:     "$syspropCmd --header-output-dir=$headerOutDir --source-output-dir=$srcOutDir --include-name=$includeName $in",
+			Command: "$syspropCmd --header-dir=$headerOutDir --system-header-dir=$systemOutDir " +
+				"--source-dir=$srcOutDir --include-name=$includeName $in",
 			CommandDeps: []string{"$syspropCmd"},
 		},
-		"headerOutDir", "srcOutDir", "includeName")
+		"headerOutDir", "systemOutDir", "srcOutDir", "includeName")
 
 	windmc = pctx.AndroidStaticRule("windmc",
 		blueprint.RuleParams{
@@ -114,6 +115,7 @@
 
 func genSysprop(ctx android.ModuleContext, syspropFile android.Path) (android.Path, android.Path) {
 	headerFile := android.PathForModuleGen(ctx, "sysprop", "include", syspropFile.Rel()+".h")
+	systemHeaderFile := android.PathForModuleGen(ctx, "sysprop/system", "include", syspropFile.Rel()+".h")
 	cppFile := android.PathForModuleGen(ctx, "sysprop", syspropFile.Rel()+".cpp")
 
 	ctx.Build(pctx, android.BuildParams{
@@ -124,6 +126,7 @@
 		Input:          syspropFile,
 		Args: map[string]string{
 			"headerOutDir": filepath.Dir(headerFile.String()),
+			"systemOutDir": filepath.Dir(systemHeaderFile.String()),
 			"srcOutDir":    filepath.Dir(cppFile.String()),
 			"includeName":  syspropFile.Rel() + ".h",
 		},
diff --git a/cc/library.go b/cc/library.go
index a6c7bc8..a48b45d 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -67,6 +67,11 @@
 		Export_proto_headers *bool
 	}
 
+	Sysprop struct {
+		// Whether platform owns this sysprop library.
+		Platform *bool
+	}
+
 	Static_ndk_lib *bool
 
 	Stubs struct {
@@ -836,9 +841,27 @@
 	}
 
 	if library.baseCompiler.hasSrcExt(".sysprop") {
-		flags := []string{
+		internalFlags := []string{
 			"-I" + android.PathForModuleGen(ctx, "sysprop", "include").String(),
 		}
+		systemFlags := []string{
+			"-I" + android.PathForModuleGen(ctx, "sysprop/system", "include").String(),
+		}
+
+		flags := internalFlags
+
+		if library.Properties.Sysprop.Platform != nil {
+			isProduct := ctx.ProductSpecific() && !ctx.useVndk()
+			isVendor := ctx.useVndk()
+			isOwnerPlatform := Bool(library.Properties.Sysprop.Platform)
+
+			useSystem := isProduct || (isOwnerPlatform == isVendor)
+
+			if useSystem {
+				flags = systemFlags
+			}
+		}
+
 		library.reexportFlags(flags)
 		library.reexportDeps(library.baseCompiler.pathDeps)
 		library.reuseExportedFlags = append(library.reuseExportedFlags, flags...)
diff --git a/cc/linker.go b/cc/linker.go
index dbdcd57..649185a 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -225,14 +225,9 @@
 	}
 
 	if ctx.toolchain().Bionic() {
-		// Allow individual projects to opt out of libcrt,builtins
-		// b/117565638
+		// libclang_rt.builtins, libgcc and libatomic have to be last on the command line
 		if !Bool(linker.Properties.No_libcrt) {
-			// libclang_rt.builtins, libgcc and libatomic have to be last on the command line
-			// TODO: Also enable for libc and libm
-			if ctx.ModuleName() != "libc" && ctx.ModuleName() != "libm" {
-				deps.LateStaticLibs = append(deps.LateStaticLibs, config.BuiltinsRuntimeLibrary(ctx.toolchain()))
-			}
+			deps.LateStaticLibs = append(deps.LateStaticLibs, config.BuiltinsRuntimeLibrary(ctx.toolchain()))
 		}
 
 		deps.LateStaticLibs = append(deps.LateStaticLibs, "libatomic")
diff --git a/cc/sysprop.go b/cc/sysprop.go
new file mode 100644
index 0000000..656f79f
--- /dev/null
+++ b/cc/sysprop.go
@@ -0,0 +1,47 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// 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 (
+	"sync"
+
+	"android/soong/android"
+)
+
+type syspropLibraryInterface interface {
+	CcModuleName() string
+}
+
+var (
+	syspropImplLibrariesKey  = android.NewOnceKey("syspropImplLibirares")
+	syspropImplLibrariesLock sync.Mutex
+)
+
+func syspropImplLibraries(config android.Config) map[string]string {
+	return config.Once(syspropImplLibrariesKey, func() interface{} {
+		return make(map[string]string)
+	}).(map[string]string)
+}
+
+// gather list of sysprop libraries
+func SyspropMutator(mctx android.BottomUpMutatorContext) {
+	if m, ok := mctx.Module().(syspropLibraryInterface); ok {
+		syspropImplLibraries := syspropImplLibraries(mctx.Config())
+		syspropImplLibrariesLock.Lock()
+		defer syspropImplLibrariesLock.Unlock()
+
+		syspropImplLibraries[mctx.ModuleName()] = m.CcModuleName()
+	}
+}
diff --git a/cc/testing.go b/cc/testing.go
new file mode 100644
index 0000000..b3b2756
--- /dev/null
+++ b/cc/testing.go
@@ -0,0 +1,188 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// 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 (
+	"android/soong/android"
+)
+
+func GatherRequiredDepsForTest(os android.OsType) string {
+	ret := `
+		toolchain_library {
+			name: "libatomic",
+			vendor_available: true,
+			recovery_available: true,
+			src: "",
+		}
+
+		toolchain_library {
+			name: "libcompiler_rt-extras",
+			vendor_available: true,
+			recovery_available: true,
+			src: "",
+		}
+
+		toolchain_library {
+			name: "libclang_rt.builtins-arm-android",
+			vendor_available: true,
+			recovery_available: true,
+			src: "",
+		}
+
+		toolchain_library {
+			name: "libclang_rt.builtins-aarch64-android",
+			vendor_available: true,
+			recovery_available: true,
+			src: "",
+		}
+
+		toolchain_library {
+			name: "libclang_rt.builtins-i686-android",
+			vendor_available: true,
+			recovery_available: true,
+			src: "",
+		}
+
+		toolchain_library {
+			name: "libclang_rt.builtins-x86_64-android",
+			vendor_available: true,
+			recovery_available: true,
+			src: "",
+		}
+
+		toolchain_library {
+			name: "libgcc",
+			vendor_available: true,
+			recovery_available: true,
+			src: "",
+		}
+
+		cc_library {
+			name: "libbase",
+			no_libgcc: true,
+			nocrt: true,
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+				support_system_process: true,
+			}
+		}
+		cc_library {
+			name: "libc",
+			no_libgcc: true,
+			nocrt: true,
+			system_shared_libs: [],
+			recovery_available: true,
+		}
+		llndk_library {
+			name: "libc",
+			symbol_file: "",
+		}
+		cc_library {
+			name: "libm",
+			no_libgcc: true,
+			nocrt: true,
+			system_shared_libs: [],
+			recovery_available: true,
+		}
+		llndk_library {
+			name: "libm",
+			symbol_file: "",
+		}
+		cc_library {
+			name: "libdl",
+			no_libgcc: true,
+			nocrt: true,
+			system_shared_libs: [],
+			recovery_available: true,
+		}
+		llndk_library {
+			name: "libdl",
+			symbol_file: "",
+		}
+		cc_library {
+			name: "libc++_static",
+			no_libgcc: true,
+			nocrt: true,
+			system_shared_libs: [],
+			stl: "none",
+			vendor_available: true,
+			recovery_available: true,
+		}
+		cc_library {
+			name: "libc++",
+			no_libgcc: true,
+			nocrt: true,
+			system_shared_libs: [],
+			stl: "none",
+			vendor_available: true,
+			recovery_available: true,
+			vndk: {
+				enabled: true,
+				support_system_process: true,
+			},
+		}
+		cc_library {
+			name: "libunwind_llvm",
+			no_libgcc: true,
+			nocrt: true,
+			system_shared_libs: [],
+			stl: "none",
+			vendor_available: true,
+			recovery_available: true,
+		}
+
+		cc_object {
+			name: "crtbegin_so",
+			recovery_available: true,
+			vendor_available: true,
+		}
+
+		cc_object {
+			name: "crtbegin_static",
+			recovery_available: true,
+			vendor_available: true,
+		}
+
+		cc_object {
+			name: "crtend_so",
+			recovery_available: true,
+			vendor_available: true,
+		}
+
+		cc_object {
+			name: "crtend_android",
+			recovery_available: true,
+			vendor_available: true,
+		}
+
+		cc_library {
+			name: "libprotobuf-cpp-lite",
+		}
+		`
+	if os == android.Fuchsia {
+		ret += `
+		cc_library {
+			name: "libbioniccompat",
+			stl: "none",
+		}
+		cc_library {
+			name: "libcompiler_rt",
+			stl: "none",
+		}
+		`
+	}
+	return ret
+}
diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go
index ecaf876..40c694f 100644
--- a/dexpreopt/dexpreopt_test.go
+++ b/dexpreopt/dexpreopt_test.go
@@ -100,7 +100,7 @@
 		t.Error(err)
 	}
 
-	wantInstalls := []android.RuleBuilderInstall{
+	wantInstalls := android.RuleBuilderInstalls{
 		{"out/test/oat/arm/package.odex", "/system/app/test/oat/arm/test.odex"},
 		{"out/test/oat/arm/package.vdex", "/system/app/test/oat/arm/test.vdex"},
 	}
@@ -141,7 +141,7 @@
 		t.Error(err)
 	}
 
-	wantInstalls := []android.RuleBuilderInstall{
+	wantInstalls := android.RuleBuilderInstalls{
 		{"out/test/oat/arm/package.odex", "/system_other/app/test/oat/arm/test.odex"},
 		{"out/test/oat/arm/package.vdex", "/system_other/app/test/oat/arm/test.vdex"},
 	}
@@ -164,7 +164,7 @@
 		t.Error(err)
 	}
 
-	wantInstalls := []android.RuleBuilderInstall{
+	wantInstalls := android.RuleBuilderInstalls{
 		{"out/test/profile.prof", "/system/app/test/test.apk.prof"},
 		{"out/test/oat/arm/package.art", "/system/app/test/oat/arm/test.art"},
 		{"out/test/oat/arm/package.odex", "/system/app/test/oat/arm/test.odex"},
diff --git a/java/androidmk.go b/java/androidmk.go
index d86e71f..04b328d 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -65,7 +65,7 @@
 					fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", library.dexJarFile.String())
 				}
 				if len(library.dexpreopter.builtInstalled) > 0 {
-					fmt.Fprintln(w, "LOCAL_SOONG_BUILT_INSTALLED :=", strings.Join(library.dexpreopter.builtInstalled, " "))
+					fmt.Fprintln(w, "LOCAL_SOONG_BUILT_INSTALLED :=", library.dexpreopter.builtInstalled)
 				}
 				fmt.Fprintln(w, "LOCAL_SDK_VERSION :=", library.sdkVersion())
 				fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", library.implementationAndResourcesJar.String())
@@ -166,7 +166,7 @@
 						fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", binary.dexJarFile.String())
 					}
 					if len(binary.dexpreopter.builtInstalled) > 0 {
-						fmt.Fprintln(w, "LOCAL_SOONG_BUILT_INSTALLED :=", strings.Join(binary.dexpreopter.builtInstalled, " "))
+						fmt.Fprintln(w, "LOCAL_SOONG_BUILT_INSTALLED :=", binary.dexpreopter.builtInstalled)
 					}
 				},
 			},
@@ -260,7 +260,7 @@
 					fmt.Fprintln(w, "LOCAL_SOONG_JNI_LIBS_"+jniLib.target.Arch.ArchType.String(), "+=", jniLib.name)
 				}
 				if len(app.dexpreopter.builtInstalled) > 0 {
-					fmt.Fprintln(w, "LOCAL_SOONG_BUILT_INSTALLED :=", strings.Join(app.dexpreopter.builtInstalled, " "))
+					fmt.Fprintln(w, "LOCAL_SOONG_BUILT_INSTALLED :=", app.dexpreopter.builtInstalled)
 				}
 			},
 		},
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index a89731a..127deab 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -28,7 +28,7 @@
 	isTest          bool
 	isInstallable   bool
 
-	builtInstalled []string
+	builtInstalled string
 }
 
 type DexpreoptProperties struct {
@@ -196,9 +196,7 @@
 
 	dexpreoptRule.Build(pctx, ctx, "dexpreopt", "dexpreopt")
 
-	for _, install := range dexpreoptRule.Installs() {
-		d.builtInstalled = append(d.builtInstalled, install.From+":"+install.To)
-	}
+	d.builtInstalled = dexpreoptRule.Installs().String()
 
 	stripRule, err := dexpreopt.GenerateStripRule(globalConfig, dexpreoptConfig)
 	if err != nil {
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 787c4d7..1a70d49 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -599,6 +599,9 @@
 		case ".aidl":
 			javaFile := genAidl(ctx, srcFile, flags.aidlFlags)
 			outSrcFiles = append(outSrcFiles, javaFile)
+		case ".sysprop":
+			javaFile := genSysprop(ctx, srcFile)
+			outSrcFiles = append(outSrcFiles, javaFile)
 		default:
 			outSrcFiles = append(outSrcFiles, srcFile)
 		}
diff --git a/java/java_test.go b/java/java_test.go
index 57b2a59..034e905 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -90,14 +90,14 @@
 	ctx.RegisterModuleType("droiddoc", android.ModuleFactoryAdaptor(DroiddocFactory))
 	ctx.RegisterModuleType("droiddoc_host", android.ModuleFactoryAdaptor(DroiddocHostFactory))
 	ctx.RegisterModuleType("droiddoc_template", android.ModuleFactoryAdaptor(ExportedDroiddocDirFactory))
-	ctx.RegisterModuleType("java_sdk_library", android.ModuleFactoryAdaptor(sdkLibraryFactory))
-	ctx.RegisterModuleType("prebuilt_apis", android.ModuleFactoryAdaptor(prebuiltApisFactory))
+	ctx.RegisterModuleType("java_sdk_library", android.ModuleFactoryAdaptor(SdkLibraryFactory))
+	ctx.RegisterModuleType("prebuilt_apis", android.ModuleFactoryAdaptor(PrebuiltApisFactory))
 	ctx.PreArchMutators(android.RegisterPrebuiltsPreArchMutators)
 	ctx.PreArchMutators(android.RegisterPrebuiltsPostDepsMutators)
 	ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
 	ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.TopDown("prebuilt_apis", prebuiltApisMutator).Parallel()
-		ctx.TopDown("java_sdk_library", sdkLibraryMutator).Parallel()
+		ctx.TopDown("prebuilt_apis", PrebuiltApisMutator).Parallel()
+		ctx.TopDown("java_sdk_library", SdkLibraryMutator).Parallel()
 	})
 	ctx.RegisterPreSingletonType("overlay", android.SingletonFactoryAdaptor(OverlaySingletonFactory))
 	ctx.RegisterPreSingletonType("sdk", android.SingletonFactoryAdaptor(sdkSingletonFactory))
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
index 0410daf..49cc931 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -30,10 +30,10 @@
 // It also creates <module>-api.<scope>.latest for the lastest <ver>.
 //
 func init() {
-	android.RegisterModuleType("prebuilt_apis", prebuiltApisFactory)
+	android.RegisterModuleType("prebuilt_apis", PrebuiltApisFactory)
 
 	android.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.TopDown("prebuilt_apis", prebuiltApisMutator).Parallel()
+		ctx.TopDown("prebuilt_apis", PrebuiltApisMutator).Parallel()
 	})
 }
 
@@ -176,14 +176,14 @@
 	}
 }
 
-func prebuiltApisMutator(mctx android.TopDownMutatorContext) {
+func PrebuiltApisMutator(mctx android.TopDownMutatorContext) {
 	if _, ok := mctx.Module().(*prebuiltApis); ok {
 		prebuiltApiFiles(mctx)
 		prebuiltSdkStubs(mctx)
 	}
 }
 
-func prebuiltApisFactory() android.Module {
+func PrebuiltApisFactory() android.Module {
 	module := &prebuiltApis{}
 	module.AddProperties(&module.properties)
 	android.InitAndroidModule(module)
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 3623e7c..f2df49b 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -42,6 +42,10 @@
 	name string
 }
 
+type syspropLibraryInterface interface {
+	SyspropJavaModule() *SdkLibrary
+}
+
 var (
 	publicApiStubsTag = dependencyTag{name: "public"}
 	systemApiStubsTag = dependencyTag{name: "system"}
@@ -74,10 +78,10 @@
 // 2) HTML generation
 
 func init() {
-	android.RegisterModuleType("java_sdk_library", sdkLibraryFactory)
+	android.RegisterModuleType("java_sdk_library", SdkLibraryFactory)
 
 	android.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.TopDown("java_sdk_library", sdkLibraryMutator).Parallel()
+		ctx.TopDown("java_sdk_library", SdkLibraryMutator).Parallel()
 	})
 
 	android.RegisterMakeVarsProvider(pctx, func(ctx android.MakeVarsContext) {
@@ -133,7 +137,7 @@
 	//Html_doc *bool
 }
 
-type sdkLibrary struct {
+type SdkLibrary struct {
 	Library
 
 	sdkLibraryProperties sdkLibraryProperties
@@ -151,10 +155,10 @@
 	testApiFilePath   android.Path
 }
 
-var _ Dependency = (*sdkLibrary)(nil)
-var _ SdkLibraryDependency = (*sdkLibrary)(nil)
+var _ Dependency = (*SdkLibrary)(nil)
+var _ SdkLibraryDependency = (*SdkLibrary)(nil)
 
-func (module *sdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
+func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
 	// Add dependencies to the stubs library
 	ctx.AddVariationDependencies(nil, publicApiStubsTag, module.stubsName(apiScopePublic))
 	ctx.AddVariationDependencies(nil, publicApiFileTag, module.docsName(apiScopePublic))
@@ -169,7 +173,7 @@
 	module.Library.deps(ctx)
 }
 
-func (module *sdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	module.Library.GenerateAndroidBuildActions(ctx)
 
 	// Record the paths to the header jars of the library (stubs and impl).
@@ -207,7 +211,7 @@
 	})
 }
 
-func (module *sdkLibrary) AndroidMk() android.AndroidMkData {
+func (module *SdkLibrary) AndroidMk() android.AndroidMkData {
 	data := module.Library.AndroidMk()
 	data.Required = append(data.Required, module.xmlFileName())
 
@@ -267,7 +271,7 @@
 }
 
 // Module name of the stubs library
-func (module *sdkLibrary) stubsName(apiScope apiScope) string {
+func (module *SdkLibrary) stubsName(apiScope apiScope) string {
 	stubsName := module.BaseModuleName() + sdkStubsLibrarySuffix
 	switch apiScope {
 	case apiScopeSystem:
@@ -279,7 +283,7 @@
 }
 
 // Module name of the docs
-func (module *sdkLibrary) docsName(apiScope apiScope) string {
+func (module *SdkLibrary) docsName(apiScope apiScope) string {
 	docsName := module.BaseModuleName() + sdkDocsSuffix
 	switch apiScope {
 	case apiScopeSystem:
@@ -291,12 +295,12 @@
 }
 
 // Module name of the runtime implementation library
-func (module *sdkLibrary) implName() string {
+func (module *SdkLibrary) implName() string {
 	return module.BaseModuleName()
 }
 
 // File path to the runtime implementation library
-func (module *sdkLibrary) implPath() string {
+func (module *SdkLibrary) implPath() string {
 	partition := "system"
 	if module.SocSpecific() {
 		partition = "vendor"
@@ -309,14 +313,14 @@
 }
 
 // Module name of the XML file for the lib
-func (module *sdkLibrary) xmlFileName() string {
+func (module *SdkLibrary) xmlFileName() string {
 	return module.BaseModuleName() + sdkXmlFileSuffix
 }
 
 // SDK version that the stubs library is built against. Note that this is always
 // *current. Older stubs library built with a numberd SDK version is created from
 // the prebuilt jar.
-func (module *sdkLibrary) sdkVersion(apiScope apiScope) string {
+func (module *SdkLibrary) sdkVersion(apiScope apiScope) string {
 	switch apiScope {
 	case apiScopePublic:
 		return "current"
@@ -332,7 +336,7 @@
 // $(INTERNAL_PLATFORM_<apiTagName>_API_FILE) points to the generated
 // api file for the current source
 // TODO: remove this when apicheck is done in soong
-func (module *sdkLibrary) apiTagName(apiScope apiScope) string {
+func (module *SdkLibrary) apiTagName(apiScope apiScope) string {
 	apiTagName := strings.Replace(strings.ToUpper(module.BaseModuleName()), ".", "_", -1)
 	switch apiScope {
 	case apiScopeSystem:
@@ -343,7 +347,7 @@
 	return apiTagName
 }
 
-func (module *sdkLibrary) latestApiFilegroupName(apiScope apiScope) string {
+func (module *SdkLibrary) latestApiFilegroupName(apiScope apiScope) string {
 	name := ":" + module.BaseModuleName() + ".api."
 	switch apiScope {
 	case apiScopePublic:
@@ -357,7 +361,7 @@
 	return name
 }
 
-func (module *sdkLibrary) latestRemovedApiFilegroupName(apiScope apiScope) string {
+func (module *SdkLibrary) latestRemovedApiFilegroupName(apiScope apiScope) string {
 	name := ":" + module.BaseModuleName() + "-removed.api."
 	switch apiScope {
 	case apiScopePublic:
@@ -372,7 +376,7 @@
 }
 
 // Creates a static java library that has API stubs
-func (module *sdkLibrary) createStubsLibrary(mctx android.TopDownMutatorContext, apiScope apiScope) {
+func (module *SdkLibrary) createStubsLibrary(mctx android.TopDownMutatorContext, apiScope apiScope) {
 	props := struct {
 		Name              *string
 		Srcs              []string
@@ -431,7 +435,7 @@
 
 // Creates a droiddoc module that creates stubs source files from the given full source
 // files
-func (module *sdkLibrary) createDocs(mctx android.TopDownMutatorContext, apiScope apiScope) {
+func (module *SdkLibrary) createDocs(mctx android.TopDownMutatorContext, apiScope apiScope) {
 	props := struct {
 		Name                             *string
 		Srcs                             []string
@@ -528,7 +532,7 @@
 }
 
 // Creates the xml file that publicizes the runtime library
-func (module *sdkLibrary) createXmlFile(mctx android.TopDownMutatorContext) {
+func (module *SdkLibrary) createXmlFile(mctx android.TopDownMutatorContext) {
 	template := `
 <?xml version="1.0" encoding="utf-8"?>
 <!-- Copyright (C) 2018 The Android Open Source Project
@@ -587,7 +591,7 @@
 	mctx.CreateModule(android.ModuleFactoryAdaptor(android.PrebuiltEtcFactory), &etcProps)
 }
 
-func (module *sdkLibrary) PrebuiltJars(ctx android.BaseContext, sdkVersion string) android.Paths {
+func (module *SdkLibrary) PrebuiltJars(ctx android.BaseContext, sdkVersion string) android.Paths {
 	var api, v string
 	if sdkVersion == "" {
 		api = "system"
@@ -607,7 +611,7 @@
 }
 
 // to satisfy SdkLibraryDependency interface
-func (module *sdkLibrary) SdkHeaderJars(ctx android.BaseContext, sdkVersion string) android.Paths {
+func (module *SdkLibrary) SdkHeaderJars(ctx android.BaseContext, sdkVersion string) android.Paths {
 	// This module is just a wrapper for the stubs.
 	if ctx.Config().UnbundledBuildPrebuiltSdks() {
 		return module.PrebuiltJars(ctx, sdkVersion)
@@ -623,7 +627,7 @@
 }
 
 // to satisfy SdkLibraryDependency interface
-func (module *sdkLibrary) SdkImplementationJars(ctx android.BaseContext, sdkVersion string) android.Paths {
+func (module *SdkLibrary) SdkImplementationJars(ctx android.BaseContext, sdkVersion string) android.Paths {
 	// This module is just a wrapper for the stubs.
 	if ctx.Config().UnbundledBuildPrebuiltSdks() {
 		return module.PrebuiltJars(ctx, sdkVersion)
@@ -649,42 +653,47 @@
 // For a java_sdk_library module, create internal modules for stubs, docs,
 // runtime libs and xml file. If requested, the stubs and docs are created twice
 // once for public API level and once for system API level
-func sdkLibraryMutator(mctx android.TopDownMutatorContext) {
-	if module, ok := mctx.Module().(*sdkLibrary); ok {
-		if module.Library.Module.properties.Srcs == nil {
-			mctx.PropertyErrorf("srcs", "java_sdk_library must specify srcs")
-		}
-
-		if module.sdkLibraryProperties.Api_packages == nil {
-			mctx.PropertyErrorf("api_packages", "java_sdk_library must specify api_packages")
-		}
-		// for public API stubs
-		module.createStubsLibrary(mctx, apiScopePublic)
-		module.createDocs(mctx, apiScopePublic)
-
-		if !Bool(module.properties.No_standard_libs) {
-			// for system API stubs
-			module.createStubsLibrary(mctx, apiScopeSystem)
-			module.createDocs(mctx, apiScopeSystem)
-
-			// for test API stubs
-			module.createStubsLibrary(mctx, apiScopeTest)
-			module.createDocs(mctx, apiScopeTest)
-
-			// for runtime
-			module.createXmlFile(mctx)
-		}
-
-		// record java_sdk_library modules so that they are exported to make
-		javaSdkLibraries := javaSdkLibraries(mctx.Config())
-		javaSdkLibrariesLock.Lock()
-		defer javaSdkLibrariesLock.Unlock()
-		*javaSdkLibraries = append(*javaSdkLibraries, module.BaseModuleName())
+func SdkLibraryMutator(mctx android.TopDownMutatorContext) {
+	if module, ok := mctx.Module().(*SdkLibrary); ok {
+		module.createInternalModules(mctx)
+	} else if module, ok := mctx.Module().(syspropLibraryInterface); ok {
+		module.SyspropJavaModule().createInternalModules(mctx)
 	}
 }
 
-func sdkLibraryFactory() android.Module {
-	module := &sdkLibrary{}
+func (module *SdkLibrary) createInternalModules(mctx android.TopDownMutatorContext) {
+	if module.Library.Module.properties.Srcs == nil {
+		mctx.PropertyErrorf("srcs", "java_sdk_library must specify srcs")
+	}
+
+	if module.sdkLibraryProperties.Api_packages == nil {
+		mctx.PropertyErrorf("api_packages", "java_sdk_library must specify api_packages")
+	}
+	// for public API stubs
+	module.createStubsLibrary(mctx, apiScopePublic)
+	module.createDocs(mctx, apiScopePublic)
+
+	if !Bool(module.properties.No_standard_libs) {
+		// for system API stubs
+		module.createStubsLibrary(mctx, apiScopeSystem)
+		module.createDocs(mctx, apiScopeSystem)
+
+		// for test API stubs
+		module.createStubsLibrary(mctx, apiScopeTest)
+		module.createDocs(mctx, apiScopeTest)
+
+		// for runtime
+		module.createXmlFile(mctx)
+	}
+
+	// record java_sdk_library modules so that they are exported to make
+	javaSdkLibraries := javaSdkLibraries(mctx.Config())
+	javaSdkLibrariesLock.Lock()
+	defer javaSdkLibrariesLock.Unlock()
+	*javaSdkLibraries = append(*javaSdkLibraries, module.BaseModuleName())
+}
+
+func (module *SdkLibrary) InitSdkLibraryProperties() {
 	module.AddProperties(
 		&module.sdkLibraryProperties,
 		&module.Library.Module.properties,
@@ -695,7 +704,11 @@
 
 	module.Library.Module.properties.Installable = proptools.BoolPtr(true)
 	module.Library.Module.deviceProperties.IsSDKLibrary = true
+}
 
+func SdkLibraryFactory() android.Module {
+	module := &SdkLibrary{}
+	module.InitSdkLibraryProperties()
 	InitJavaModule(module, android.HostAndDeviceSupported)
 	return module
 }
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
new file mode 100644
index 0000000..4069e78
--- /dev/null
+++ b/sysprop/sysprop_library.go
@@ -0,0 +1,130 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// 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 sysprop
+
+import (
+	"android/soong/android"
+	"android/soong/cc"
+	"android/soong/java"
+	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
+)
+
+type dependencyTag struct {
+	blueprint.BaseDependencyTag
+	name string
+}
+
+type syspropLibrary struct {
+	java.SdkLibrary
+
+	commonProperties         commonProperties
+	syspropLibraryProperties syspropLibraryProperties
+}
+
+type syspropLibraryProperties struct {
+	// Determine who owns this sysprop library. Possible values are
+	// "Platform", "Vendor", or "Odm"
+	Property_owner string
+	Api_packages   []string
+}
+
+type commonProperties struct {
+	Srcs             []string
+	Recovery         *bool
+	Vendor_available *bool
+}
+
+var (
+	Bool         = proptools.Bool
+	syspropCcTag = dependencyTag{name: "syspropCc"}
+)
+
+func init() {
+	android.RegisterModuleType("sysprop_library", syspropLibraryFactory)
+}
+
+func (m *syspropLibrary) CcModuleName() string {
+	return "lib" + m.Name()
+}
+
+func (m *syspropLibrary) SyspropJavaModule() *java.SdkLibrary {
+	return &m.SdkLibrary
+}
+
+func syspropLibraryFactory() android.Module {
+	m := &syspropLibrary{}
+
+	m.AddProperties(
+		&m.commonProperties,
+		&m.syspropLibraryProperties,
+	)
+	m.InitSdkLibraryProperties()
+	android.InitAndroidMultiTargetsArchModule(m, android.DeviceSupported, "common")
+	android.AddLoadHook(m, func(ctx android.LoadHookContext) { syspropLibraryHook(ctx, m) })
+
+	return m
+}
+
+func syspropLibraryHook(ctx android.LoadHookContext, m *syspropLibrary) {
+	if m.syspropLibraryProperties.Api_packages == nil {
+		ctx.PropertyErrorf("api_packages", "sysprop_library must specify api_packages")
+	}
+
+	socSpecific := ctx.SocSpecific()
+	deviceSpecific := ctx.DeviceSpecific()
+	productSpecific := ctx.ProductSpecific()
+
+	owner := m.syspropLibraryProperties.Property_owner
+
+	switch owner {
+	case "Platform":
+		// Every partition can access platform-defined properties
+		break
+	case "Vendor":
+		// System can't access vendor's properties
+		if !socSpecific && !deviceSpecific && !productSpecific {
+			ctx.ModuleErrorf("None of soc_specific, device_specific, product_specific is true. " +
+				"System can't access sysprop_library owned by Vendor")
+		}
+	case "Odm":
+		// Only vendor can access Odm-defined properties
+		if !socSpecific && !deviceSpecific {
+			ctx.ModuleErrorf("Neither soc_speicifc nor device_specific is true. " +
+				"Odm-defined properties should be accessed only in Vendor or Odm")
+		}
+	default:
+		ctx.PropertyErrorf("property_owner",
+			"Unknown value %s: must be one of Platform, Vendor or Odm", owner)
+	}
+
+	ccProps := struct {
+		Name             *string
+		Soc_specific     *bool
+		Device_specific  *bool
+		Product_specific *bool
+		Sysprop          struct {
+			Platform *bool
+		}
+	}{}
+
+	ccProps.Name = proptools.StringPtr(m.CcModuleName())
+	ccProps.Soc_specific = proptools.BoolPtr(socSpecific)
+	ccProps.Device_specific = proptools.BoolPtr(deviceSpecific)
+	ccProps.Product_specific = proptools.BoolPtr(productSpecific)
+	ccProps.Sysprop.Platform = proptools.BoolPtr(owner == "Platform")
+
+	ctx.CreateModule(android.ModuleFactoryAdaptor(cc.LibraryFactory), &m.commonProperties, &ccProps)
+}
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
new file mode 100644
index 0000000..92e0af4
--- /dev/null
+++ b/sysprop/sysprop_test.go
@@ -0,0 +1,380 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// 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 sysprop
+
+import (
+	"android/soong/android"
+	"android/soong/cc"
+	"android/soong/java"
+
+	"fmt"
+	"io/ioutil"
+	"os"
+	"strings"
+	"testing"
+
+	"github.com/google/blueprint/proptools"
+)
+
+var buildDir string
+
+func setUp() {
+	var err error
+	buildDir, err = ioutil.TempDir("", "soong_sysprop_test")
+	if err != nil {
+		panic(err)
+	}
+}
+
+func tearDown() {
+	os.RemoveAll(buildDir)
+}
+
+func TestMain(m *testing.M) {
+	run := func() int {
+		setUp()
+		defer tearDown()
+
+		return m.Run()
+	}
+
+	os.Exit(run())
+}
+
+func testContext(config android.Config, bp string,
+	fs map[string][]byte) *android.TestContext {
+
+	ctx := android.NewTestArchContext()
+	ctx.RegisterModuleType("android_app", android.ModuleFactoryAdaptor(java.AndroidAppFactory))
+	ctx.RegisterModuleType("droiddoc_template", android.ModuleFactoryAdaptor(java.ExportedDroiddocDirFactory))
+	ctx.RegisterModuleType("java_library", android.ModuleFactoryAdaptor(java.LibraryFactory))
+	ctx.RegisterModuleType("java_system_modules", android.ModuleFactoryAdaptor(java.SystemModulesFactory))
+	ctx.RegisterModuleType("prebuilt_apis", android.ModuleFactoryAdaptor(java.PrebuiltApisFactory))
+	ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.TopDown("load_hooks", android.LoadHookMutator).Parallel()
+	})
+	ctx.PreArchMutators(android.RegisterPrebuiltsPreArchMutators)
+	ctx.PreArchMutators(android.RegisterPrebuiltsPostDepsMutators)
+	ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
+	ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.TopDown("prebuilt_apis", java.PrebuiltApisMutator).Parallel()
+		ctx.TopDown("java_sdk_library", java.SdkLibraryMutator).Parallel()
+	})
+
+	ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory))
+	ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(cc.ObjectFactory))
+	ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(cc.LlndkLibraryFactory))
+	ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(cc.ToolchainLibraryFactory))
+	ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.BottomUp("image", cc.ImageMutator).Parallel()
+		ctx.BottomUp("link", cc.LinkageMutator).Parallel()
+		ctx.BottomUp("vndk", cc.VndkMutator).Parallel()
+		ctx.BottomUp("version", cc.VersionMutator).Parallel()
+		ctx.BottomUp("begin", cc.BeginMutator).Parallel()
+		ctx.BottomUp("sysprop", cc.SyspropMutator).Parallel()
+	})
+
+	ctx.RegisterModuleType("sysprop_library", android.ModuleFactoryAdaptor(syspropLibraryFactory))
+
+	ctx.Register()
+
+	extraModules := []string{
+		"core-lambda-stubs",
+		"framework",
+		"ext",
+		"updatable_media_stubs",
+
+		"android_stubs_current",
+		"android_system_stubs_current",
+		"android_test_stubs_current",
+		"core.current.stubs",
+		"core.platform.api.stubs",
+	}
+
+	for _, extra := range extraModules {
+		bp += fmt.Sprintf(`
+			java_library {
+				name: "%s",
+				srcs: ["a.java"],
+				no_standard_libs: true,
+				sdk_version: "core_current",
+				system_modules: "core-platform-api-stubs-system-modules",
+			}
+		`, extra)
+	}
+
+	bp += `
+		android_app {
+			name: "framework-res",
+			no_framework_libs: true,
+		}
+	`
+
+	systemModules := []string{
+		"core-system-modules",
+		"core-platform-api-stubs-system-modules",
+		"android_stubs_current_system_modules",
+		"android_system_stubs_current_system_modules",
+		"android_test_stubs_current_system_modules",
+	}
+
+	for _, extra := range systemModules {
+		bp += fmt.Sprintf(`
+			java_system_modules {
+				name: "%s",
+			}
+		`, extra)
+	}
+
+	bp += cc.GatherRequiredDepsForTest(android.Android)
+
+	mockFS := map[string][]byte{
+		"Android.bp":             []byte(bp),
+		"a.java":                 nil,
+		"b.java":                 nil,
+		"c.java":                 nil,
+		"d.cpp":                  nil,
+		"api/current.txt":        nil,
+		"api/removed.txt":        nil,
+		"api/system-current.txt": nil,
+		"api/system-removed.txt": nil,
+		"api/test-current.txt":   nil,
+		"api/test-removed.txt":   nil,
+
+		"prebuilts/sdk/current/core/android.jar":                              nil,
+		"prebuilts/sdk/current/public/android.jar":                            nil,
+		"prebuilts/sdk/current/public/framework.aidl":                         nil,
+		"prebuilts/sdk/current/public/core.jar":                               nil,
+		"prebuilts/sdk/current/system/android.jar":                            nil,
+		"prebuilts/sdk/current/test/android.jar":                              nil,
+		"prebuilts/sdk/28/public/api/sysprop-platform.txt":                    nil,
+		"prebuilts/sdk/28/system/api/sysprop-platform.txt":                    nil,
+		"prebuilts/sdk/28/test/api/sysprop-platform.txt":                      nil,
+		"prebuilts/sdk/28/public/api/sysprop-platform-removed.txt":            nil,
+		"prebuilts/sdk/28/system/api/sysprop-platform-removed.txt":            nil,
+		"prebuilts/sdk/28/test/api/sysprop-platform-removed.txt":              nil,
+		"prebuilts/sdk/28/public/api/sysprop-platform-on-product.txt":         nil,
+		"prebuilts/sdk/28/system/api/sysprop-platform-on-product.txt":         nil,
+		"prebuilts/sdk/28/test/api/sysprop-platform-on-product.txt":           nil,
+		"prebuilts/sdk/28/public/api/sysprop-platform-on-product-removed.txt": nil,
+		"prebuilts/sdk/28/system/api/sysprop-platform-on-product-removed.txt": nil,
+		"prebuilts/sdk/28/test/api/sysprop-platform-on-product-removed.txt":   nil,
+		"prebuilts/sdk/28/public/api/sysprop-vendor.txt":                      nil,
+		"prebuilts/sdk/28/system/api/sysprop-vendor.txt":                      nil,
+		"prebuilts/sdk/28/test/api/sysprop-vendor.txt":                        nil,
+		"prebuilts/sdk/28/public/api/sysprop-vendor-removed.txt":              nil,
+		"prebuilts/sdk/28/system/api/sysprop-vendor-removed.txt":              nil,
+		"prebuilts/sdk/28/test/api/sysprop-vendor-removed.txt":                nil,
+		"prebuilts/sdk/tools/core-lambda-stubs.jar":                           nil,
+		"prebuilts/sdk/Android.bp":                                            []byte(`prebuilt_apis { name: "sdk", api_dirs: ["28", "current"],}`),
+
+		// For framework-res, which is an implicit dependency for framework
+		"AndroidManifest.xml":                   nil,
+		"build/target/product/security/testkey": nil,
+
+		"build/soong/scripts/jar-wrapper.sh": nil,
+
+		"build/make/core/proguard.flags":             nil,
+		"build/make/core/proguard_basic_keeps.flags": nil,
+
+		"jdk8/jre/lib/jce.jar": nil,
+		"jdk8/jre/lib/rt.jar":  nil,
+		"jdk8/lib/tools.jar":   nil,
+
+		"bar-doc/a.java":                 nil,
+		"bar-doc/b.java":                 nil,
+		"bar-doc/IFoo.aidl":              nil,
+		"bar-doc/known_oj_tags.txt":      nil,
+		"external/doclava/templates-sdk": nil,
+
+		"cert/new_cert.x509.pem": nil,
+		"cert/new_cert.pk8":      nil,
+
+		"android/sysprop/PlatformProperties.sysprop": nil,
+		"com/android/VendorProperties.sysprop":       nil,
+	}
+
+	for k, v := range fs {
+		mockFS[k] = v
+	}
+
+	ctx.MockFileSystem(mockFS)
+
+	return ctx
+}
+
+func run(t *testing.T, ctx *android.TestContext, config android.Config) {
+	t.Helper()
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp", "prebuilts/sdk/Android.bp"})
+	android.FailIfErrored(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	android.FailIfErrored(t, errs)
+}
+
+func testConfig(env map[string]string) android.Config {
+	if env == nil {
+		env = make(map[string]string)
+	}
+	if env["ANDROID_JAVA8_HOME"] == "" {
+		env["ANDROID_JAVA8_HOME"] = "jdk8"
+	}
+	config := android.TestArchConfig(buildDir, env)
+	config.TestProductVariables.DeviceSystemSdkVersions = []string{"28"}
+	config.TestProductVariables.DeviceVndkVersion = proptools.StringPtr("current")
+	config.TestProductVariables.Platform_vndk_version = proptools.StringPtr("VER")
+	return config
+
+}
+
+func test(t *testing.T, bp string) *android.TestContext {
+	t.Helper()
+	config := testConfig(nil)
+	ctx := testContext(config, bp, nil)
+	run(t, ctx, config)
+
+	return ctx
+}
+
+func TestSyspropLibrary(t *testing.T) {
+	ctx := test(t, `
+		sysprop_library {
+			name: "sysprop-platform",
+			srcs: ["android/sysprop/PlatformProperties.sysprop"],
+			api_packages: ["android.sysprop"],
+			property_owner: "Platform",
+			vendor_available: true,
+		}
+
+		sysprop_library {
+			name: "sysprop-platform-on-product",
+			srcs: ["android/sysprop/PlatformProperties.sysprop"],
+			api_packages: ["android.sysprop"],
+			property_owner: "Platform",
+			product_specific: true,
+		}
+
+		sysprop_library {
+			name: "sysprop-vendor",
+			srcs: ["com/android/VendorProperties.sysprop"],
+			api_packages: ["com.android"],
+			property_owner: "Vendor",
+			product_specific: true,
+			vendor_available: true,
+		}
+
+		java_library {
+			name: "java-platform",
+			srcs: ["c.java"],
+			sdk_version: "system_current",
+			libs: ["sysprop-platform"],
+		}
+
+		java_library {
+			name: "java-product",
+			srcs: ["c.java"],
+			sdk_version: "system_current",
+			product_specific: true,
+			libs: ["sysprop-platform", "sysprop-vendor"],
+		}
+
+		java_library {
+			name: "java-vendor",
+			srcs: ["c.java"],
+			sdk_version: "system_current",
+			soc_specific: true,
+			libs: ["sysprop-platform", "sysprop-vendor"],
+		}
+
+		cc_library {
+			name: "cc-client-platform",
+			srcs: ["d.cpp"],
+			static_libs: ["sysprop-platform"],
+		}
+
+		cc_library {
+			name: "cc-client-product",
+			srcs: ["d.cpp"],
+			product_specific: true,
+			static_libs: ["sysprop-platform-on-product", "sysprop-vendor"],
+		}
+
+		cc_library {
+			name: "cc-client-vendor",
+			srcs: ["d.cpp"],
+			soc_specific: true,
+			static_libs: ["sysprop-platform", "sysprop-vendor"],
+		}
+		`)
+
+	for _, variant := range []string{
+		"android_arm_armv7-a-neon_core_shared",
+		"android_arm_armv7-a-neon_core_static",
+		"android_arm_armv7-a-neon_vendor_shared",
+		"android_arm_armv7-a-neon_vendor_static",
+		"android_arm64_armv8-a_core_shared",
+		"android_arm64_armv8-a_core_static",
+		"android_arm64_armv8-a_vendor_shared",
+		"android_arm64_armv8-a_vendor_static",
+	} {
+		// Check for generated cc_library
+		ctx.ModuleForTests("libsysprop-platform", variant)
+		ctx.ModuleForTests("libsysprop-vendor", variant)
+	}
+
+	ctx.ModuleForTests("sysprop-platform", "android_common")
+	ctx.ModuleForTests("sysprop-vendor", "android_common")
+
+	// Check for exported includes
+	coreVariant := "android_arm64_armv8-a_core_static"
+	vendorVariant := "android_arm64_armv8-a_vendor_static"
+
+	platformInternalPath := "libsysprop-platform/android_arm64_armv8-a_core_static/gen/sysprop/include"
+	platformSystemCorePath := "libsysprop-platform/android_arm64_armv8-a_core_static/gen/sysprop/system/include"
+	platformSystemVendorPath := "libsysprop-platform/android_arm64_armv8-a_vendor_static/gen/sysprop/system/include"
+
+	platformOnProductPath := "libsysprop-platform-on-product/android_arm64_armv8-a_core_static/gen/sysprop/system/include"
+
+	vendorInternalPath := "libsysprop-vendor/android_arm64_armv8-a_vendor_static/gen/sysprop/include"
+	vendorSystemPath := "libsysprop-vendor/android_arm64_armv8-a_core_static/gen/sysprop/system/include"
+
+	platformClient := ctx.ModuleForTests("cc-client-platform", coreVariant)
+	platformFlags := platformClient.Rule("cc").Args["cFlags"]
+
+	// Platform should use platform's internal header
+	if !strings.Contains(platformFlags, platformInternalPath) {
+		t.Errorf("flags for platform must contain %#v, but was %#v.",
+			platformInternalPath, platformFlags)
+	}
+
+	productClient := ctx.ModuleForTests("cc-client-product", coreVariant)
+	productFlags := productClient.Rule("cc").Args["cFlags"]
+
+	// Product should use platform's and vendor's system headers
+	if !strings.Contains(productFlags, platformOnProductPath) ||
+		!strings.Contains(productFlags, vendorSystemPath) {
+		t.Errorf("flags for product must contain %#v and %#v, but was %#v.",
+			platformSystemCorePath, vendorSystemPath, productFlags)
+	}
+
+	vendorClient := ctx.ModuleForTests("cc-client-vendor", vendorVariant)
+	vendorFlags := vendorClient.Rule("cc").Args["cFlags"]
+
+	// Vendor should use platform's system header and vendor's internal header
+	if !strings.Contains(vendorFlags, platformSystemVendorPath) ||
+		!strings.Contains(vendorFlags, vendorInternalPath) {
+		t.Errorf("flags for vendor must contain %#v and %#v, but was %#v.",
+			platformSystemVendorPath, vendorInternalPath, vendorFlags)
+	}
+}
diff --git a/ui/build/goma.go b/ui/build/goma.go
index 015a7c7..ff0b40e 100644
--- a/ui/build/goma.go
+++ b/ui/build/goma.go
@@ -73,7 +73,7 @@
 
 	cmd := Command(ctx, config, "goma_ctl.py ensure_start", gomaCtl, "ensure_start")
 
-	if err := cmd.Run(); err != nil {
-		ctx.Fatalf("goma_ctl.py ensure_start failed with: %v\n", err)
+	if output, err := cmd.CombinedOutput(); err != nil {
+		ctx.Fatalf("goma_ctl.py ensure_start failed with: %v\n%s\n", err, output)
 	}
 }