Merge "neverallows in Soong"
diff --git a/android/androidmk.go b/android/androidmk.go
index fb3934f..704b560 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -230,9 +230,15 @@
 		if Bool(amod.commonProperties.Proprietary) {
 			fmt.Fprintln(&data.preamble, "LOCAL_PROPRIETARY_MODULE := true")
 		}
-		if Bool(amod.commonProperties.Vendor) {
+		if Bool(amod.commonProperties.Vendor) || Bool(amod.commonProperties.Soc_specific) {
 			fmt.Fprintln(&data.preamble, "LOCAL_VENDOR_MODULE := true")
 		}
+		if Bool(amod.commonProperties.Device_specific) {
+			fmt.Fprintln(&data.preamble, "LOCAL_ODM_MODULE := true")
+		}
+		if Bool(amod.commonProperties.Product_specific) {
+			fmt.Fprintln(&data.preamble, "LOCAL_OEM_MODULE := true")
+		}
 		if amod.commonProperties.Owner != nil {
 			fmt.Fprintln(&data.preamble, "LOCAL_MODULE_OWNER :=", *amod.commonProperties.Owner)
 		}
diff --git a/android/arch.go b/android/arch.go
index af3919c..3a22569 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -971,7 +971,7 @@
 
 func getNdkAbisConfig() []archConfig {
 	return []archConfig{
-		{"arm", "armv5te", "", []string{"armeabi"}},
+		{"arm", "armv7-a", "", []string{"armeabi"}},
 		{"arm64", "armv8-a", "", []string{"arm64-v8a"}},
 		{"x86", "", "", []string{"x86"}},
 		{"x86_64", "", "", []string{"x86_64"}},
diff --git a/android/config.go b/android/config.go
index 56e9525..887291d 100644
--- a/android/config.go
+++ b/android/config.go
@@ -584,6 +584,10 @@
 	return false
 }
 
+func (c *config) UseD8Desugar() bool {
+	return c.IsEnvTrue("USE_D8_DESUGAR")
+}
+
 func (c *config) UseGoma() bool {
 	return Bool(c.ProductVariables.UseGoma)
 }
@@ -657,6 +661,20 @@
 	return c.config.ProductVariables.ExtraVndkVersions
 }
 
+func (c *deviceConfig) OdmPath() string {
+	if c.config.ProductVariables.OdmPath != nil {
+		return *c.config.ProductVariables.OdmPath
+	}
+	return "odm"
+}
+
+func (c *deviceConfig) OemPath() string {
+	if c.config.ProductVariables.OemPath != nil {
+		return *c.config.ProductVariables.OemPath
+	}
+	return "oem"
+}
+
 func (c *deviceConfig) BtConfigIncludeDir() string {
 	return String(c.config.ProductVariables.BtConfigIncludeDir)
 }
diff --git a/android/module.go b/android/module.go
index 3d8f683..cb068ab 100644
--- a/android/module.go
+++ b/android/module.go
@@ -65,7 +65,10 @@
 	Windows() bool
 	Debug() bool
 	PrimaryArch() bool
-	InstallOnVendorPartition() bool
+	Platform() bool
+	DeviceSpecific() bool
+	SocSpecific() bool
+	ProductSpecific() bool
 	AConfig() Config
 	DeviceConfig() DeviceConfig
 }
@@ -212,9 +215,26 @@
 	// vendor who owns this module
 	Owner *string
 
-	// whether this module is device specific and should be installed into /vendor
+	// whether this module is specific to an SoC (System-On-a-Chip). When set to true,
+	// it is installed into /vendor (or /system/vendor if vendor partition does not exist).
+	// Use `soc_specific` instead for better meaning.
 	Vendor *bool
 
+	// whether this module is specific to an SoC (System-On-a-Chip). When set to true,
+	// it is installed into /vendor (or /system/vendor if vendor partition does not exist).
+	Soc_specific *bool
+
+	// whether this module is specific to a device, not only for SoC, but also for off-chip
+	// peripherals. When set to true, it is installed into /odm (or /vendor/odm if odm partition
+	// does not exist, or /system/vendor/odm if both odm and vendor partitions do not exist).
+	// This implies `soc_specific:true`.
+	Device_specific *bool
+
+	// whether this module is specific to a software configuration of a product (e.g. country,
+	// network operator, etc). When set to true, it is installed into /oem (or /system/oem if
+	// oem partition does not exist).
+	Product_specific *bool
+
 	// init.rc files to be installed if this module is installed
 	Init_rc []string
 
@@ -264,6 +284,30 @@
 	NeitherHostNorDeviceSupported
 )
 
+type moduleKind int
+
+const (
+	platformModule moduleKind = iota
+	deviceSpecificModule
+	socSpecificModule
+	productSpecificModule
+)
+
+func (k moduleKind) String() string {
+	switch k {
+	case platformModule:
+		return "platform"
+	case deviceSpecificModule:
+		return "device-specific"
+	case socSpecificModule:
+		return "soc-specific"
+	case productSpecificModule:
+		return "product-specific"
+	default:
+		panic(fmt.Errorf("unknown module kind %d", k))
+	}
+}
+
 func InitAndroidModule(m Module) {
 	base := m.base()
 	base.module = m
@@ -546,11 +590,48 @@
 	}
 }
 
+func determineModuleKind(a *ModuleBase, ctx blueprint.BaseModuleContext) moduleKind {
+	var socSpecific = Bool(a.commonProperties.Vendor) || Bool(a.commonProperties.Proprietary) || Bool(a.commonProperties.Soc_specific)
+	var deviceSpecific = Bool(a.commonProperties.Device_specific)
+	var productSpecific = Bool(a.commonProperties.Product_specific)
+
+	if ((socSpecific || deviceSpecific) && productSpecific) || (socSpecific && deviceSpecific) {
+		msg := "conflicting value set here"
+		if productSpecific {
+			ctx.PropertyErrorf("product_specific", "a module cannot be specific to SoC or device and product at the same time.")
+			if deviceSpecific {
+				ctx.PropertyErrorf("device_specific", msg)
+			}
+		} else {
+			ctx.PropertyErrorf("device_specific", "a module cannot be specific to SoC and device at the same time.")
+		}
+		if Bool(a.commonProperties.Vendor) {
+			ctx.PropertyErrorf("vendor", msg)
+		}
+		if Bool(a.commonProperties.Proprietary) {
+			ctx.PropertyErrorf("proprietary", msg)
+		}
+		if Bool(a.commonProperties.Soc_specific) {
+			ctx.PropertyErrorf("soc_specific", msg)
+		}
+	}
+
+	if productSpecific {
+		return productSpecificModule
+	} else if deviceSpecific {
+		return deviceSpecificModule
+	} else if socSpecific {
+		return socSpecificModule
+	} else {
+		return platformModule
+	}
+}
+
 func (a *ModuleBase) androidBaseContextFactory(ctx blueprint.BaseModuleContext) androidBaseContextImpl {
 	return androidBaseContextImpl{
 		target:        a.commonProperties.CompileTarget,
 		targetPrimary: a.commonProperties.CompilePrimary,
-		vendor:        Bool(a.commonProperties.Proprietary) || Bool(a.commonProperties.Vendor),
+		kind:          determineModuleKind(a, ctx),
 		config:        ctx.Config().(Config),
 	}
 }
@@ -606,7 +687,7 @@
 	target        Target
 	targetPrimary bool
 	debug         bool
-	vendor        bool
+	kind          moduleKind
 	config        Config
 }
 
@@ -867,8 +948,20 @@
 	return DeviceConfig{a.config.deviceConfig}
 }
 
-func (a *androidBaseContextImpl) InstallOnVendorPartition() bool {
-	return a.vendor
+func (a *androidBaseContextImpl) Platform() bool {
+	return a.kind == platformModule
+}
+
+func (a *androidBaseContextImpl) DeviceSpecific() bool {
+	return a.kind == deviceSpecificModule
+}
+
+func (a *androidBaseContextImpl) SocSpecific() bool {
+	return a.kind == socSpecificModule
+}
+
+func (a *androidBaseContextImpl) ProductSpecific() bool {
+	return a.kind == productSpecificModule
 }
 
 func (a *androidModuleContext) InstallInData() bool {
diff --git a/android/paths.go b/android/paths.go
index e47b9e4..4d9c858 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -845,8 +845,12 @@
 		var partition string
 		if ctx.InstallInData() {
 			partition = "data"
-		} else if ctx.InstallOnVendorPartition() {
+		} else if ctx.SocSpecific() {
 			partition = ctx.DeviceConfig().VendorPath()
+		} else if ctx.DeviceSpecific() {
+			partition = ctx.DeviceConfig().OdmPath()
+		} else if ctx.ProductSpecific() {
+			partition = ctx.DeviceConfig().OemPath()
 		} else {
 			partition = "system"
 		}
diff --git a/android/paths_test.go b/android/paths_test.go
index 1e4ba53..110974f 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -246,12 +246,34 @@
 			ctx: &moduleInstallPathContextImpl{
 				androidBaseContextImpl: androidBaseContextImpl{
 					target: deviceTarget,
-					vendor: true,
+					kind:   socSpecificModule,
 				},
 			},
 			in:  []string{"bin", "my_test"},
 			out: "target/product/test_device/vendor/bin/my_test",
 		},
+		{
+			name: "odm binary",
+			ctx: &moduleInstallPathContextImpl{
+				androidBaseContextImpl: androidBaseContextImpl{
+					target: deviceTarget,
+					kind:   deviceSpecificModule,
+				},
+			},
+			in:  []string{"bin", "my_test"},
+			out: "target/product/test_device/odm/bin/my_test",
+		},
+		{
+			name: "oem binary",
+			ctx: &moduleInstallPathContextImpl{
+				androidBaseContextImpl: androidBaseContextImpl{
+					target: deviceTarget,
+					kind:   productSpecificModule,
+				},
+			},
+			in:  []string{"bin", "my_test"},
+			out: "target/product/test_device/oem/bin/my_test",
+		},
 
 		{
 			name: "system native test binary",
@@ -269,7 +291,31 @@
 			ctx: &moduleInstallPathContextImpl{
 				androidBaseContextImpl: androidBaseContextImpl{
 					target: deviceTarget,
-					vendor: true,
+					kind:   socSpecificModule,
+				},
+				inData: true,
+			},
+			in:  []string{"nativetest", "my_test"},
+			out: "target/product/test_device/data/nativetest/my_test",
+		},
+		{
+			name: "odm native test binary",
+			ctx: &moduleInstallPathContextImpl{
+				androidBaseContextImpl: androidBaseContextImpl{
+					target: deviceTarget,
+					kind:   deviceSpecificModule,
+				},
+				inData: true,
+			},
+			in:  []string{"nativetest", "my_test"},
+			out: "target/product/test_device/data/nativetest/my_test",
+		},
+		{
+			name: "oem native test binary",
+			ctx: &moduleInstallPathContextImpl{
+				androidBaseContextImpl: androidBaseContextImpl{
+					target: deviceTarget,
+					kind:   productSpecificModule,
 				},
 				inData: true,
 			},
@@ -293,13 +339,37 @@
 			ctx: &moduleInstallPathContextImpl{
 				androidBaseContextImpl: androidBaseContextImpl{
 					target: deviceTarget,
-					vendor: true,
+					kind:   socSpecificModule,
 				},
 				inSanitizerDir: true,
 			},
 			in:  []string{"bin", "my_test"},
 			out: "target/product/test_device/data/asan/vendor/bin/my_test",
 		},
+		{
+			name: "sanitized odm binary",
+			ctx: &moduleInstallPathContextImpl{
+				androidBaseContextImpl: androidBaseContextImpl{
+					target: deviceTarget,
+					kind:   deviceSpecificModule,
+				},
+				inSanitizerDir: true,
+			},
+			in:  []string{"bin", "my_test"},
+			out: "target/product/test_device/data/asan/odm/bin/my_test",
+		},
+		{
+			name: "sanitized oem binary",
+			ctx: &moduleInstallPathContextImpl{
+				androidBaseContextImpl: androidBaseContextImpl{
+					target: deviceTarget,
+					kind:   productSpecificModule,
+				},
+				inSanitizerDir: true,
+			},
+			in:  []string{"bin", "my_test"},
+			out: "target/product/test_device/data/asan/oem/bin/my_test",
+		},
 
 		{
 			name: "sanitized system native test binary",
@@ -318,7 +388,33 @@
 			ctx: &moduleInstallPathContextImpl{
 				androidBaseContextImpl: androidBaseContextImpl{
 					target: deviceTarget,
-					vendor: true,
+					kind:   socSpecificModule,
+				},
+				inData:         true,
+				inSanitizerDir: true,
+			},
+			in:  []string{"nativetest", "my_test"},
+			out: "target/product/test_device/data/asan/data/nativetest/my_test",
+		},
+		{
+			name: "sanitized odm native test binary",
+			ctx: &moduleInstallPathContextImpl{
+				androidBaseContextImpl: androidBaseContextImpl{
+					target: deviceTarget,
+					kind:   deviceSpecificModule,
+				},
+				inData:         true,
+				inSanitizerDir: true,
+			},
+			in:  []string{"nativetest", "my_test"},
+			out: "target/product/test_device/data/asan/data/nativetest/my_test",
+		},
+		{
+			name: "sanitized oem native test binary",
+			ctx: &moduleInstallPathContextImpl{
+				androidBaseContextImpl: androidBaseContextImpl{
+					target: deviceTarget,
+					kind:   productSpecificModule,
 				},
 				inData:         true,
 				inSanitizerDir: true,
diff --git a/android/proto.go b/android/proto.go
index 1c70656..0cf7c26 100644
--- a/android/proto.go
+++ b/android/proto.go
@@ -23,7 +23,9 @@
 // generate the source.
 
 func ProtoFlags(ctx ModuleContext, p *ProtoProperties) []string {
-	var protoFlags []string
+	// -I . must come first, it affects where protoc places the output files.
+	protoFlags := []string{"-I ."}
+
 	if len(p.Proto.Local_include_dirs) > 0 {
 		localProtoIncludeDirs := PathsForModuleSrc(ctx, p.Proto.Local_include_dirs)
 		protoFlags = append(protoFlags, JoinWithPrefix(localProtoIncludeDirs.Strings(), "-I"))
@@ -33,8 +35,6 @@
 		protoFlags = append(protoFlags, JoinWithPrefix(rootProtoIncludeDirs.Strings(), "-I"))
 	}
 
-	protoFlags = append(protoFlags, "-I .")
-
 	return protoFlags
 }
 
diff --git a/android/variable.go b/android/variable.go
index f585599..6962b0f 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -67,23 +67,11 @@
 			Cflags []string
 		}
 
-		// treble is true when a build is a Treble compliant device.  This is automatically set when
-		// a build is shipped with Android O, but can be overriden.  This controls such things as
-		// the sepolicy split and enabling the Treble linker namespaces.
-		// TODO(b/62019611): remove
-		Treble struct {
-			Cflags []string
-		}
-
 		// treble_linker_namespaces is true when the system/vendor linker namespace separation is
 		// enabled.
 		Treble_linker_namespaces struct {
 			Cflags []string
 		}
-		// sepolicy_split is true when system/vendor sepolicy split is enabled.
-		Sepolicy_split struct {
-			Cflags []string
-		}
 		// enforce_vintf_manifest is true when a device is required to have a vintf manifest.
 		Enforce_vintf_manifest struct {
 			Cflags []string
@@ -172,7 +160,6 @@
 	Debuggable                 *bool `json:",omitempty"`
 	Eng                        *bool `json:",omitempty"`
 	Device_uses_hwc2           *bool `json:",omitempty"`
-	Treble                     *bool `json:",omitempty"`
 	Treble_linker_namespaces   *bool `json:",omitempty"`
 	Sepolicy_split             *bool `json:",omitempty"`
 	Enforce_vintf_manifest     *bool `json:",omitempty"`
@@ -187,6 +174,8 @@
 	CFIIncludePaths *[]string `json:",omitempty"`
 
 	VendorPath *string `json:",omitempty"`
+	OdmPath    *string `json:",omitempty"`
+	OemPath    *string `json:",omitempty"`
 
 	ClangTidy  *bool   `json:",omitempty"`
 	TidyChecks *string `json:",omitempty"`
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index c6e90f0..82b5eb9 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -152,6 +152,8 @@
 			"LOCAL_TIDY":                     "tidy",
 			"LOCAL_PROPRIETARY_MODULE":       "proprietary",
 			"LOCAL_VENDOR_MODULE":            "vendor",
+			"LOCAL_ODM_MODULE":               "device_specific",
+			"LOCAL_OEM_MODULE":               "product_specific",
 			"LOCAL_EXPORT_PACKAGE_RESOURCES": "export_package_resources",
 			"LOCAL_PRIVILEGED_MODULE":        "privileged",
 
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 1db5373..efd4ee7 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -372,3 +372,14 @@
 		fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
 	})
 }
+
+func (c *ndkPrebuiltStlLinker) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+	ret.Class = "SHARED_LIBRARIES"
+
+	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+		// Prevent make from installing the libraries to obj/lib (since we have
+		// dozens of libraries with the same name, they'll clobber each other
+		// and the real versions of the libraries from the platform).
+		fmt.Fprintln(w, "LOCAL_COPY_TO_INTERMEDIATE_LIBRARIES := false")
+	})
+}
diff --git a/cc/builder.go b/cc/builder.go
index b5f4c5c..de85d6e 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -231,27 +231,28 @@
 }
 
 type builderFlags struct {
-	globalFlags   string
-	arFlags       string
-	asFlags       string
-	cFlags        string
-	toolingCFlags string // A separate set of Cflags for clang LibTooling tools
-	conlyFlags    string
-	cppFlags      string
-	ldFlags       string
-	libFlags      string
-	yaccFlags     string
-	protoFlags    string
-	tidyFlags     string
-	sAbiFlags     string
-	yasmFlags     string
-	aidlFlags     string
-	rsFlags       string
-	toolchain     config.Toolchain
-	clang         bool
-	tidy          bool
-	coverage      bool
-	sAbiDump      bool
+	globalFlags    string
+	arFlags        string
+	asFlags        string
+	cFlags         string
+	toolingCFlags  string // A separate set of Cflags for clang LibTooling tools
+	conlyFlags     string
+	cppFlags       string
+	ldFlags        string
+	libFlags       string
+	yaccFlags      string
+	protoFlags     string
+	protoOutParams string
+	tidyFlags      string
+	sAbiFlags      string
+	yasmFlags      string
+	aidlFlags      string
+	rsFlags        string
+	toolchain      config.Toolchain
+	clang          bool
+	tidy           bool
+	coverage       bool
+	sAbiDump       bool
 
 	systemIncludeFlags string
 
@@ -289,7 +290,7 @@
 
 // Generate rules for compiling multiple .c, .cpp, or .S files to individual .o files
 func TransformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles android.Paths,
-	flags builderFlags, deps android.Paths) Objects {
+	flags builderFlags, pathDeps android.Paths, genDeps android.Paths) Objects {
 
 	objFiles := make(android.Paths, len(srcFiles))
 	var tidyFiles android.Paths
@@ -362,7 +363,8 @@
 				Description: "yasm " + srcFile.Rel(),
 				Output:      objFile,
 				Input:       srcFile,
-				OrderOnly:   deps,
+				Implicits:   pathDeps,
+				OrderOnly:   genDeps,
 				Args: map[string]string{
 					"asFlags": flags.yasmFlags,
 				},
@@ -374,7 +376,8 @@
 				Description: "windres " + srcFile.Rel(),
 				Output:      objFile,
 				Input:       srcFile,
-				OrderOnly:   deps,
+				Implicits:   pathDeps,
+				OrderOnly:   genDeps,
 				Args: map[string]string{
 					"windresCmd": gccCmd(flags.toolchain, "windres"),
 					"flags":      flags.toolchain.WindresFlags(),
@@ -442,7 +445,8 @@
 			Output:          objFile,
 			ImplicitOutputs: implicitOutputs,
 			Input:           srcFile,
-			OrderOnly:       deps,
+			Implicits:       pathDeps,
+			OrderOnly:       genDeps,
 			Args: map[string]string{
 				"cFlags": moduleCflags,
 				"ccCmd":  ccCmd,
diff --git a/cc/cc.go b/cc/cc.go
index 715919f..13d0e3b 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -116,6 +116,7 @@
 	ToolingCppFlags []string // Flags that apply to C++ source files parsed by clang LibTooling tools
 	YaccFlags       []string // Flags that apply to Yacc source files
 	protoFlags      []string // Flags that apply to proto source files
+	protoOutParams  []string // Flags that modify the output of proto generated files
 	aidlFlags       []string // Flags that apply to aidl source files
 	rsFlags         []string // Flags that apply to renderscript source files
 	LdFlags         []string // Flags that apply to linker command lines
@@ -424,8 +425,9 @@
 	moduleContextImpl
 }
 
-func (ctx *moduleContext) InstallOnVendorPartition() bool {
-	return ctx.ModuleContext.InstallOnVendorPartition() || (ctx.mod.useVndk() && !ctx.mod.isVndk())
+func (ctx *moduleContext) SocSpecific() bool {
+	return ctx.ModuleContext.SocSpecific() ||
+		(ctx.mod.hasVendorVariant() && ctx.mod.useVndk() && !ctx.mod.isVndk())
 }
 
 type moduleContextImpl struct {
@@ -1035,6 +1037,27 @@
 		ctx.ModuleErrorf("links %q built against newer API version %q",
 			ctx.OtherModuleName(to), String(to.Properties.Sdk_version))
 	}
+
+	// Also check that the two STL choices are compatible.
+	fromStl := from.stl.Properties.SelectedStl
+	toStl := to.stl.Properties.SelectedStl
+	if fromStl == "" || toStl == "" {
+		// Libraries that don't use the STL are unrestricted.
+		return
+	}
+
+	if fromStl == "ndk_system" || toStl == "ndk_system" {
+		// We can be permissive with the system "STL" since it is only the C++
+		// ABI layer, but in the future we should make sure that everyone is
+		// using either libc++ or nothing.
+		return
+	}
+
+	if getNdkStlFamily(ctx, from) != getNdkStlFamily(ctx, to) {
+		ctx.ModuleErrorf("uses %q and depends on %q which uses incompatible %q",
+			from.stl.Properties.SelectedStl, ctx.OtherModuleName(to),
+			to.stl.Properties.SelectedStl)
+	}
 }
 
 // Convert dependencies to paths.  Returns a PathDeps containing paths
@@ -1380,7 +1403,7 @@
 				mctx.CreateVariations(coreMode)
 			} else if Bool(props.Vendor_available) {
 				mctx.CreateVariations(coreMode, vendorMode)
-			} else if mctx.InstallOnVendorPartition() {
+			} else if mctx.SocSpecific() || mctx.DeviceSpecific() {
 				mctx.CreateVariations(vendorMode)
 			} else {
 				mctx.CreateVariations(coreMode)
@@ -1394,9 +1417,9 @@
 	}
 
 	// Sanity check
-	if m.VendorProperties.Vendor_available != nil && mctx.InstallOnVendorPartition() {
+	if m.VendorProperties.Vendor_available != nil && (mctx.SocSpecific() || mctx.DeviceSpecific()) {
 		mctx.PropertyErrorf("vendor_available",
-			"doesn't make sense at the same time as `vendor: true` or `proprietary: true`")
+			"doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific:true`")
 		return
 	}
 	if vndk := m.vndkdep; vndk != nil {
@@ -1438,8 +1461,8 @@
 		vendor := mod[1].(*Module)
 		vendor.Properties.UseVndk = true
 		squashVendorSrcs(vendor)
-	} else if mctx.InstallOnVendorPartition() && String(m.Properties.Sdk_version) == "" {
-		// This will be available in /vendor only
+	} else if (mctx.SocSpecific() || mctx.DeviceSpecific()) && String(m.Properties.Sdk_version) == "" {
+		// This will be available in /vendor (or /odm) only
 		mod := mctx.CreateVariations(vendorMode)
 		vendor := mod[0].(*Module)
 		vendor.Properties.UseVndk = true
diff --git a/cc/compiler.go b/cc/compiler.go
index 40dbea4..7e8e8b8 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -148,6 +148,9 @@
 
 	// Stores the original list of source files before being cleared by library reuse
 	OriginalSrcs []string `blueprint:"mutated"`
+
+	// Build and link with OpenMP
+	Openmp *bool `android:"arch_variant"`
 }
 
 func NewBaseCompiler() *baseCompiler {
@@ -157,7 +160,8 @@
 type baseCompiler struct {
 	Properties BaseCompilerProperties
 	Proto      android.ProtoProperties
-	deps       android.Paths
+	genDeps    android.Paths
+	pathDeps   android.Paths
 	flags      builderFlags
 
 	// Sources that were passed to the C/C++ compiler
@@ -203,6 +207,10 @@
 		deps = protoDeps(ctx, deps, &compiler.Proto, Bool(compiler.Properties.Proto.Static))
 	}
 
+	if Bool(compiler.Properties.Openmp) {
+		deps.StaticLibs = append(deps.StaticLibs, "libomp")
+	}
+
 	return deps
 }
 
@@ -493,6 +501,10 @@
 		}
 	}
 
+	if Bool(compiler.Properties.Openmp) {
+		flags.CFlags = append(flags.CFlags, "-fopenmp")
+	}
+
 	return flags
 }
 
@@ -522,7 +534,7 @@
 	if ctx.useSdk() {
 		// The NDK sysroot timestamp file depends on all the NDK sysroot files
 		// (headers and libraries).
-		return android.Paths{getNdkSysrootTimestampFile(ctx)}
+		return android.Paths{getNdkBaseTimestampFile(ctx)}
 	}
 	return nil
 }
@@ -536,17 +548,16 @@
 	srcs := append(android.Paths(nil), compiler.srcsBeforeGen...)
 
 	srcs, genDeps := genSources(ctx, srcs, buildFlags)
-
-	pathDeps = append(pathDeps, genDeps...)
 	pathDeps = append(pathDeps, flags.CFlagsDeps...)
 
-	compiler.deps = pathDeps
+	compiler.pathDeps = pathDeps
+	compiler.genDeps = genDeps
 
 	// Save src, buildFlags and context
 	compiler.srcs = srcs
 
 	// Compile files listed in c.Properties.Srcs into objects
-	objs := compileObjs(ctx, buildFlags, "", srcs, compiler.deps)
+	objs := compileObjs(ctx, buildFlags, "", srcs, pathDeps, genDeps)
 
 	if ctx.Failed() {
 		return Objects{}
@@ -557,7 +568,7 @@
 
 // Compile a list of source files into objects a specified subdirectory
 func compileObjs(ctx android.ModuleContext, flags builderFlags,
-	subdir string, srcFiles, deps android.Paths) Objects {
+	subdir string, srcFiles, pathDeps android.Paths, genDeps android.Paths) Objects {
 
-	return TransformSourceToObj(ctx, subdir, srcFiles, flags, deps)
+	return TransformSourceToObj(ctx, subdir, srcFiles, flags, pathDeps, genDeps)
 }
diff --git a/cc/config/global.go b/cc/config/global.go
index 6f4b3e2..c10c60a 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -120,17 +120,13 @@
 	ClangDefaultShortVersion = "5.0.1"
 
 	WarningAllowedProjects = []string{
-		"external/skia/",
 		"device/",
 		"vendor/",
 	}
 
 	// Some Android.mk files still have warnings.
 	WarningAllowedOldProjects = []string{
-		"frameworks/av/drm/mediacas/plugins/",
-		"hardware/libhardware/modules/",
 		"hardware/qcom/",
-		"tools/adt/idea/android/ultimate/get_modification_time/jni/",
 	}
 )
 
diff --git a/cc/gen.go b/cc/gen.go
index 15b37b5..e9d1e2a 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -153,7 +153,8 @@
 			srcFiles[i] = cppFile
 			genLex(ctx, srcFile, cppFile)
 		case ".proto":
-			ccFile, headerFile := genProto(ctx, srcFile, buildFlags.protoFlags)
+			ccFile, headerFile := genProto(ctx, srcFile, buildFlags.protoFlags,
+				buildFlags.protoOutParams)
 			srcFiles[i] = ccFile
 			deps = append(deps, headerFile)
 		case ".aidl":
diff --git a/cc/gen_stub_libs.py b/cc/gen_stub_libs.py
index abb39c2..8c99bbf 100755
--- a/cc/gen_stub_libs.py
+++ b/cc/gen_stub_libs.py
@@ -244,6 +244,7 @@
         tags = decode_api_level_tags(tags, self.api_map)
         symbols = []
         global_scope = True
+        cpp_symbols = False
         while self.next_line() != '':
             if '}' in self.current_line:
                 # Line is something like '} BASE; # tags'. Both base and tags
@@ -252,12 +253,17 @@
                 base = base.partition('#')[0].strip()
                 if not base.endswith(';'):
                     raise ParseError(
-                        'Unterminated version block (expected ;).')
-                base = base.rstrip(';').rstrip()
-                if base == '':
-                    base = None
-                return Version(name, base, tags, symbols)
-            elif ':' in self.current_line:
+                        'Unterminated version/export "C++" block (expected ;).')
+                if cpp_symbols:
+                    cpp_symbols = False
+                else:
+                    base = base.rstrip(';').rstrip()
+                    if base == '':
+                        base = None
+                    return Version(name, base, tags, symbols)
+            elif 'extern "C++" {' in self.current_line:
+                cpp_symbols = True
+            elif not cpp_symbols and ':' in self.current_line:
                 visibility = self.current_line.split(':')[0].strip()
                 if visibility == 'local':
                     global_scope = False
@@ -265,10 +271,10 @@
                     global_scope = True
                 else:
                     raise ParseError('Unknown visiblity label: ' + visibility)
-            elif global_scope:
+            elif global_scope and not cpp_symbols:
                 symbols.append(self.parse_symbol())
             else:
-                # We're in a hidden scope. Ignore everything.
+                # We're in a hidden scope or in 'extern "C++"' block. Ignore everything.
                 pass
         raise ParseError('Unexpected EOF in version block.')
 
diff --git a/cc/library.go b/cc/library.go
index b664a5e..9bd12a9 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -384,11 +384,11 @@
 	if library.static() {
 		srcs := android.PathsForModuleSrc(ctx, library.Properties.Static.Srcs)
 		objs = objs.Append(compileObjs(ctx, buildFlags, android.DeviceStaticLibrary,
-			srcs, library.baseCompiler.deps))
+			srcs, library.baseCompiler.pathDeps, library.baseCompiler.genDeps))
 	} else if library.shared() {
 		srcs := android.PathsForModuleSrc(ctx, library.Properties.Shared.Srcs)
 		objs = objs.Append(compileObjs(ctx, buildFlags, android.DeviceSharedLibrary,
-			srcs, library.baseCompiler.deps))
+			srcs, library.baseCompiler.pathDeps, library.baseCompiler.genDeps))
 	}
 
 	return objs
@@ -671,8 +671,8 @@
 			}
 			library.reexportFlags(flags)
 			library.reuseExportedFlags = append(library.reuseExportedFlags, flags...)
-			library.reexportDeps(library.baseCompiler.deps) // TODO: restrict to aidl deps
-			library.reuseExportedDeps = append(library.reuseExportedDeps, library.baseCompiler.deps...)
+			library.reexportDeps(library.baseCompiler.genDeps) // TODO: restrict to aidl deps
+			library.reuseExportedDeps = append(library.reuseExportedDeps, library.baseCompiler.genDeps...)
 		}
 	}
 
@@ -684,8 +684,8 @@
 			}
 			library.reexportFlags(flags)
 			library.reuseExportedFlags = append(library.reuseExportedFlags, flags...)
-			library.reexportDeps(library.baseCompiler.deps) // TODO: restrict to proto deps
-			library.reuseExportedDeps = append(library.reuseExportedDeps, library.baseCompiler.deps...)
+			library.reexportDeps(library.baseCompiler.genDeps) // TODO: restrict to proto deps
+			library.reuseExportedDeps = append(library.reuseExportedDeps, library.baseCompiler.genDeps...)
 		}
 	}
 
@@ -733,7 +733,8 @@
 		library.baseInstaller.install(ctx, file)
 	}
 
-	if Bool(library.Properties.Static_ndk_lib) && library.static() {
+	if Bool(library.Properties.Static_ndk_lib) && library.static() &&
+		!ctx.useVndk() && ctx.Device() {
 		installPath := getNdkSysrootBase(ctx).Join(
 			ctx, "usr/lib", ctx.toolchain().ClangTriple(), file.Base())
 
diff --git a/cc/lto.go b/cc/lto.go
index fdb7688..b1e7cfa 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -40,10 +40,15 @@
 	// Lto must violate capitialization style for acronyms so that it can be
 	// referred to in blueprint files as "lto"
 	Lto struct {
-		Full *bool `android:"arch_variant"`
-		Thin *bool `android:"arch_variant"`
+		Never *bool `android:"arch_variant"`
+		Full  *bool `android:"arch_variant"`
+		Thin  *bool `android:"arch_variant"`
 	} `android:"arch_variant"`
-	LTODep bool `blueprint:"mutated"`
+
+	// Dep properties indicate that this module needs to be built with LTO
+	// since it is an object dependency of an LTO module.
+	FullDep bool `blueprint:"mutated"`
+	ThinDep bool `blueprint:"mutated"`
 }
 
 type lto struct {
@@ -84,7 +89,7 @@
 
 // Can be called with a null receiver
 func (lto *lto) LTO() bool {
-	if lto == nil {
+	if lto == nil || lto.Disabled() {
 		return false
 	}
 
@@ -93,41 +98,91 @@
 	return full || thin
 }
 
+// Is lto.never explicitly set to true?
+func (lto *lto) Disabled() bool {
+	return lto.Properties.Lto.Never != nil && *lto.Properties.Lto.Never
+}
+
 // Propagate lto requirements down from binaries
 func ltoDepsMutator(mctx android.TopDownMutatorContext) {
-	if c, ok := mctx.Module().(*Module); ok && c.lto.LTO() {
-		full := Bool(c.lto.Properties.Lto.Full)
-		thin := Bool(c.lto.Properties.Lto.Thin)
+	if m, ok := mctx.Module().(*Module); ok && m.lto.LTO() {
+		full := Bool(m.lto.Properties.Lto.Full)
+		thin := Bool(m.lto.Properties.Lto.Thin)
 		if full && thin {
 			mctx.PropertyErrorf("LTO", "FullLTO and ThinLTO are mutually exclusive")
 		}
 
-		mctx.VisitDepsDepthFirst(func(m android.Module) {
-			tag := mctx.OtherModuleDependencyTag(m)
+		mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
+			tag := mctx.OtherModuleDependencyTag(dep)
 			switch tag {
 			case staticDepTag, staticExportDepTag, lateStaticDepTag, wholeStaticDepTag, objDepTag, reuseObjTag:
-				if cc, ok := m.(*Module); ok && cc.lto != nil {
-					cc.lto.Properties.LTODep = true
+				if dep, ok := dep.(*Module); ok && dep.lto != nil &&
+					!dep.lto.Disabled() {
+					if full && !Bool(dep.lto.Properties.Lto.Full) {
+						dep.lto.Properties.FullDep = true
+					}
+					if thin && !Bool(dep.lto.Properties.Lto.Thin) {
+						dep.lto.Properties.ThinDep = true
+					}
 				}
+
+				// Recursively walk static dependencies
+				return true
 			}
+
+			// Do not recurse down non-static dependencies
+			return false
 		})
 	}
 }
 
 // Create lto variants for modules that need them
 func ltoMutator(mctx android.BottomUpMutatorContext) {
-	if c, ok := mctx.Module().(*Module); ok && c.lto != nil {
-		if c.lto.LTO() {
-			mctx.SetDependencyVariation("lto")
-		} else if c.lto.Properties.LTODep {
-			modules := mctx.CreateVariations("", "lto")
-			modules[0].(*Module).lto.Properties.Lto.Full = boolPtr(false)
-			modules[0].(*Module).lto.Properties.Lto.Thin = boolPtr(false)
-			modules[0].(*Module).lto.Properties.LTODep = false
-			modules[1].(*Module).lto.Properties.LTODep = false
-			modules[1].(*Module).Properties.PreventInstall = true
-			modules[1].(*Module).Properties.HideFromMake = true
+	if m, ok := mctx.Module().(*Module); ok && m.lto != nil {
+		// Create variations for LTO types required as static
+		// dependencies
+		variationNames := []string{""}
+		if m.lto.Properties.FullDep && !Bool(m.lto.Properties.Lto.Full) {
+			variationNames = append(variationNames, "lto-full")
 		}
-		c.lto.Properties.LTODep = false
+		if m.lto.Properties.ThinDep && !Bool(m.lto.Properties.Lto.Thin) {
+			variationNames = append(variationNames, "lto-thin")
+		}
+
+		// Use correct dependencies if LTO property is explicitly set
+		// (mutually exclusive)
+		if Bool(m.lto.Properties.Lto.Full) {
+			mctx.SetDependencyVariation("lto-full")
+		}
+		if Bool(m.lto.Properties.Lto.Thin) {
+			mctx.SetDependencyVariation("lto-thin")
+		}
+
+		if len(variationNames) > 1 {
+			modules := mctx.CreateVariations(variationNames...)
+			for i, name := range variationNames {
+				variation := modules[i].(*Module)
+				// Default module which will be
+				// installed. Variation set above according to
+				// explicit LTO properties
+				if name == "" {
+					continue
+				}
+
+				// LTO properties for dependencies
+				if name == "lto-full" {
+					variation.lto.Properties.Lto.Full = boolPtr(true)
+					variation.lto.Properties.Lto.Thin = boolPtr(false)
+				}
+				if name == "lto-thin" {
+					variation.lto.Properties.Lto.Full = boolPtr(false)
+					variation.lto.Properties.Lto.Thin = boolPtr(true)
+				}
+				variation.Properties.PreventInstall = true
+				variation.Properties.HideFromMake = true
+				variation.lto.Properties.FullDep = false
+				variation.lto.Properties.ThinDep = false
+			}
+		}
 	}
 }
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 459d980..5a76666 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -288,7 +288,7 @@
 
 	subdir := ""
 	srcs := []android.Path{stubSrcPath}
-	return compileObjs(ctx, flagsToBuilderFlags(flags), subdir, srcs, nil), versionScriptPath
+	return compileObjs(ctx, flagsToBuilderFlags(flags), subdir, srcs, nil, nil), versionScriptPath
 }
 
 func (c *stubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
diff --git a/cc/ndk_prebuilt.go b/cc/ndk_prebuilt.go
index 13424e3..69e07b9 100644
--- a/cc/ndk_prebuilt.go
+++ b/cc/ndk_prebuilt.go
@@ -141,7 +141,10 @@
 	module.compiler = nil
 	module.linker = linker
 	module.installer = nil
-	module.Properties.HideFromMake = true
+	minVersionString := "minimum"
+	noStlString := "none"
+	module.Properties.Sdk_version = &minVersionString
+	module.stl.Properties.Stl = &noStlString
 	return module.Init()
 }
 
diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go
index 4324458..c7ba588 100644
--- a/cc/ndk_sysroot.go
+++ b/cc/ndk_sysroot.go
@@ -74,7 +74,16 @@
 	return getNdkInstallBase(ctx).Join(ctx, "sysroot")
 }
 
-func getNdkSysrootTimestampFile(ctx android.PathContext) android.WritablePath {
+// The base timestamp file depends on the NDK headers and stub shared libraries,
+// but not the static libraries. This distinction is needed because the static
+// libraries themselves might need to depend on the base sysroot.
+func getNdkBaseTimestampFile(ctx android.PathContext) android.WritablePath {
+	return android.PathForOutput(ctx, "ndk_base.timestamp")
+}
+
+// The full timestamp file depends on the base timestamp *and* the static
+// libraries.
+func getNdkFullTimestampFile(ctx android.PathContext) android.WritablePath {
 	return android.PathForOutput(ctx, "ndk.timestamp")
 }
 
@@ -85,6 +94,7 @@
 type ndkSingleton struct{}
 
 func (n *ndkSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+	var staticLibInstallPaths android.Paths
 	var installPaths android.Paths
 	var licensePaths android.Paths
 	ctx.VisitAllModules(func(module android.Module) {
@@ -109,7 +119,8 @@
 
 			if library, ok := m.linker.(*libraryDecorator); ok {
 				if library.ndkSysrootPath != nil {
-					installPaths = append(installPaths, library.ndkSysrootPath)
+					staticLibInstallPaths = append(
+						staticLibInstallPaths, library.ndkSysrootPath)
 				}
 			}
 		}
@@ -123,13 +134,21 @@
 		Inputs:      licensePaths,
 	})
 
-	depPaths := append(installPaths, combinedLicense)
+	baseDepPaths := append(installPaths, combinedLicense)
 
 	// There's a dummy "ndk" rule defined in ndk/Android.mk that depends on
 	// this. `m ndk` will build the sysroots.
 	ctx.Build(pctx, android.BuildParams{
 		Rule:      android.Touch,
-		Output:    getNdkSysrootTimestampFile(ctx),
-		Implicits: depPaths,
+		Output:    getNdkBaseTimestampFile(ctx),
+		Implicits: baseDepPaths,
+	})
+
+	fullDepPaths := append(staticLibInstallPaths, getNdkBaseTimestampFile(ctx))
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:      android.Touch,
+		Output:    getNdkFullTimestampFile(ctx),
+		Implicits: fullDepPaths,
 	})
 }
diff --git a/cc/pgo.go b/cc/pgo.go
index 9fea154..fef962e 100644
--- a/cc/pgo.go
+++ b/cc/pgo.go
@@ -42,6 +42,9 @@
 		Profile_file       *string `android:"arch_variant"`
 		Benchmarks         []string
 		Enable_profile_use *bool `android:"arch_variant"`
+		// Additional compiler flags to use when building this module
+		// for profiling (either instrumentation or sampling).
+		Cflags []string `android:"arch_variant"`
 	} `android:"arch_variant"`
 
 	PgoPresent          bool `blueprint:"mutated"`
@@ -65,6 +68,8 @@
 }
 
 func (props *PgoProperties) addProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
+	flags.CFlags = append(flags.CFlags, props.Pgo.Cflags...)
+
 	if props.isInstrumentation() {
 		flags.CFlags = append(flags.CFlags, profileInstrumentFlag)
 		// The profile runtime is added below in deps().  Add the below
diff --git a/cc/proto.go b/cc/proto.go
index e7f1d41..3b5fd3b 100644
--- a/cc/proto.go
+++ b/cc/proto.go
@@ -16,6 +16,7 @@
 
 import (
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
 )
@@ -27,15 +28,15 @@
 var (
 	proto = pctx.AndroidStaticRule("protoc",
 		blueprint.RuleParams{
-			Command:     "$protocCmd --cpp_out=$outDir $protoFlags $in",
+			Command:     "$protocCmd --cpp_out=$protoOutParams:$outDir $protoFlags $in",
 			CommandDeps: []string{"$protocCmd"},
-		}, "protoFlags", "outDir")
+		}, "protoFlags", "protoOutParams", "outDir")
 )
 
 // genProto creates a rule to convert a .proto file to generated .pb.cc and .pb.h files and returns
 // the paths to the generated files.
 func genProto(ctx android.ModuleContext, protoFile android.Path,
-	protoFlags string) (ccFile, headerFile android.WritablePath) {
+	protoFlags string, protoOutParams string) (ccFile, headerFile android.WritablePath) {
 
 	ccFile = android.GenPathWithExt(ctx, "proto", protoFile, "pb.cc")
 	headerFile = android.GenPathWithExt(ctx, "proto", protoFile, "pb.h")
@@ -46,8 +47,9 @@
 		Outputs:     android.WritablePaths{ccFile, headerFile},
 		Input:       protoFile,
 		Args: map[string]string{
-			"outDir":     android.ProtoDir(ctx).String(),
-			"protoFlags": protoFlags,
+			"outDir":         android.ProtoDir(ctx).String(),
+			"protoFlags":     protoFlags,
+			"protoOutParams": protoOutParams,
 		},
 	})
 
@@ -97,5 +99,9 @@
 
 	flags.protoFlags = android.ProtoFlags(ctx, p)
 
+	if proptools.String(p.Proto.Type) == "lite" {
+		flags.protoOutParams = []string{"lite"}
+	}
+
 	return flags
 }
diff --git a/cc/stl.go b/cc/stl.go
index 347db99..338db84 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -19,6 +19,25 @@
 	"fmt"
 )
 
+func getNdkStlFamily(ctx android.ModuleContext, m *Module) string {
+	stl := m.stl.Properties.SelectedStl
+	switch stl {
+	case "ndk_libc++_shared", "ndk_libc++_static":
+		return "libc++"
+	case "ndk_libstlport_shared", "ndk_libstlport_static":
+		return "stlport"
+	case "ndk_libgnustl_static":
+		return "gnustl"
+	case "ndk_system":
+		return "system"
+	case "":
+		return "none"
+	default:
+		ctx.ModuleErrorf("stl: %q is not a valid STL", stl)
+		return ""
+	}
+}
+
 type StlProperties struct {
 	// select the STL library to use.  Possible values are "libc++", "libc++_static",
 	// "stlport", "stlport_static", "ndk", "libstdc++", or "none".  Leave blank to select the
diff --git a/cc/tidy.go b/cc/tidy.go
index 6d7c957..67fd3db 100644
--- a/cc/tidy.go
+++ b/cc/tidy.go
@@ -77,6 +77,11 @@
 		flags.TidyFlags = append(flags.TidyFlags, headerFilter)
 	}
 
+	// If clang-tidy is not enabled globally, add the -quiet flag.
+	if !ctx.Config().ClangTidy() {
+		flags.TidyFlags = append(flags.TidyFlags, "-quiet")
+	}
+
 	// We might be using the static analyzer through clang tidy.
 	// https://bugs.llvm.org/show_bug.cgi?id=32914
 	flags.TidyFlags = append(flags.TidyFlags, "-extra-arg-before=-D__clang_analyzer__")
diff --git a/cc/util.go b/cc/util.go
index cc89af6..7041029 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -97,27 +97,28 @@
 
 func flagsToBuilderFlags(in Flags) builderFlags {
 	return builderFlags{
-		globalFlags:   strings.Join(in.GlobalFlags, " "),
-		arFlags:       strings.Join(in.ArFlags, " "),
-		asFlags:       strings.Join(in.AsFlags, " "),
-		cFlags:        strings.Join(in.CFlags, " "),
-		toolingCFlags: strings.Join(in.ToolingCFlags, " "),
-		conlyFlags:    strings.Join(in.ConlyFlags, " "),
-		cppFlags:      strings.Join(in.CppFlags, " "),
-		yaccFlags:     strings.Join(in.YaccFlags, " "),
-		protoFlags:    strings.Join(in.protoFlags, " "),
-		aidlFlags:     strings.Join(in.aidlFlags, " "),
-		rsFlags:       strings.Join(in.rsFlags, " "),
-		ldFlags:       strings.Join(in.LdFlags, " "),
-		libFlags:      strings.Join(in.libFlags, " "),
-		tidyFlags:     strings.Join(in.TidyFlags, " "),
-		sAbiFlags:     strings.Join(in.SAbiFlags, " "),
-		yasmFlags:     strings.Join(in.YasmFlags, " "),
-		toolchain:     in.Toolchain,
-		clang:         in.Clang,
-		coverage:      in.Coverage,
-		tidy:          in.Tidy,
-		sAbiDump:      in.SAbiDump,
+		globalFlags:    strings.Join(in.GlobalFlags, " "),
+		arFlags:        strings.Join(in.ArFlags, " "),
+		asFlags:        strings.Join(in.AsFlags, " "),
+		cFlags:         strings.Join(in.CFlags, " "),
+		toolingCFlags:  strings.Join(in.ToolingCFlags, " "),
+		conlyFlags:     strings.Join(in.ConlyFlags, " "),
+		cppFlags:       strings.Join(in.CppFlags, " "),
+		yaccFlags:      strings.Join(in.YaccFlags, " "),
+		protoFlags:     strings.Join(in.protoFlags, " "),
+		protoOutParams: strings.Join(in.protoOutParams, ":"),
+		aidlFlags:      strings.Join(in.aidlFlags, " "),
+		rsFlags:        strings.Join(in.rsFlags, " "),
+		ldFlags:        strings.Join(in.LdFlags, " "),
+		libFlags:       strings.Join(in.libFlags, " "),
+		tidyFlags:      strings.Join(in.TidyFlags, " "),
+		sAbiFlags:      strings.Join(in.SAbiFlags, " "),
+		yasmFlags:      strings.Join(in.YasmFlags, " "),
+		toolchain:      in.Toolchain,
+		clang:          in.Clang,
+		coverage:       in.Coverage,
+		tidy:           in.Tidy,
+		sAbiDump:       in.SAbiDump,
 
 		systemIncludeFlags: strings.Join(in.SystemIncludeFlags, " "),
 
diff --git a/cmd/merge_zips/merge_zips.go b/cmd/merge_zips/merge_zips.go
index 556dad0..df04358 100644
--- a/cmd/merge_zips/merge_zips.go
+++ b/cmd/merge_zips/merge_zips.go
@@ -19,6 +19,7 @@
 	"flag"
 	"fmt"
 	"hash/crc32"
+	"io/ioutil"
 	"log"
 	"os"
 	"path/filepath"
@@ -56,11 +57,13 @@
 var (
 	sortEntries      = flag.Bool("s", false, "sort entries (defaults to the order from the input zip files)")
 	emulateJar       = flag.Bool("j", false, "sort zip entries using jar ordering (META-INF first)")
+	emulatePar       = flag.Bool("p", false, "merge zip entries based on par format")
 	stripDirs        fileList
 	stripFiles       fileList
 	zipsToNotStrip   = make(zipsToNotStripSet)
 	stripDirEntries  = flag.Bool("D", false, "strip directory entries from the output zip file")
 	manifest         = flag.String("m", "", "manifest file to insert in jar")
+	entrypoint       = flag.String("e", "", "par entrypoint file to insert in par")
 	ignoreDuplicates = flag.Bool("ignore-duplicates", false, "take each entry from the first zip it exists in and don't warn")
 )
 
@@ -72,7 +75,7 @@
 
 func main() {
 	flag.Usage = func() {
-		fmt.Fprintln(os.Stderr, "usage: merge_zips [-jsD] [-m manifest] output [inputs...]")
+		fmt.Fprintln(os.Stderr, "usage: merge_zips [-jpsD] [-m manifest] [-e entrypoint] output [inputs...]")
 		flag.PrintDefaults()
 	}
 
@@ -118,8 +121,13 @@
 		log.Fatal(errors.New("must specify -j when specifying a manifest via -m"))
 	}
 
+	if *entrypoint != "" && !*emulatePar {
+		log.Fatal(errors.New("must specify -p when specifying a entrypoint via -e"))
+	}
+
 	// do merge
-	err = mergeZips(readers, writer, *manifest, *sortEntries, *emulateJar, *stripDirEntries, *ignoreDuplicates)
+	err = mergeZips(readers, writer, *manifest, *entrypoint, *sortEntries, *emulateJar, *emulatePar,
+		*stripDirEntries, *ignoreDuplicates)
 	if err != nil {
 		log.Fatal(err)
 	}
@@ -210,8 +218,8 @@
 	source zipSource
 }
 
-func mergeZips(readers []namedZipReader, writer *zip.Writer, manifest string,
-	sortEntries, emulateJar, stripDirEntries, ignoreDuplicates bool) error {
+func mergeZips(readers []namedZipReader, writer *zip.Writer, manifest, entrypoint string,
+	sortEntries, emulateJar, emulatePar, stripDirEntries, ignoreDuplicates bool) error {
 
 	sourceByDest := make(map[string]zipSource, 0)
 	orderedMappings := []fileMapping{}
@@ -244,6 +252,68 @@
 		addMapping(jar.ManifestFile, fileSource)
 	}
 
+	if entrypoint != "" {
+		buf, err := ioutil.ReadFile(entrypoint)
+		if err != nil {
+			return err
+		}
+		fh := &zip.FileHeader{
+			Name:               "entry_point.txt",
+			Method:             zip.Store,
+			UncompressedSize64: uint64(len(buf)),
+		}
+		fh.SetMode(0700)
+		fh.SetModTime(jar.DefaultTime)
+		fileSource := bufferEntry{fh, buf}
+		addMapping("entry_point.txt", fileSource)
+	}
+
+	if emulatePar {
+		// the runfiles packages needs to be populated with "__init__.py".
+		newPyPkgs := []string{}
+		// the runfiles dirs have been treated as packages.
+		existingPyPkgSet := make(map[string]bool)
+		// put existing __init__.py files to a set first. This set is used for preventing
+		// generated __init__.py files from overwriting existing ones.
+		for _, namedReader := range readers {
+			for _, file := range namedReader.reader.File {
+				if filepath.Base(file.Name) != "__init__.py" {
+					continue
+				}
+				pyPkg := pathBeforeLastSlash(file.Name)
+				if _, found := existingPyPkgSet[pyPkg]; found {
+					panic(fmt.Errorf("found __init__.py path duplicates during pars merging: %q.", file.Name))
+				} else {
+					existingPyPkgSet[pyPkg] = true
+				}
+			}
+		}
+		for _, namedReader := range readers {
+			for _, file := range namedReader.reader.File {
+				var parentPath string /* the path after trimming last "/" */
+				if filepath.Base(file.Name) == "__init__.py" {
+					// for existing __init__.py files, we should trim last "/" for twice.
+					// eg. a/b/c/__init__.py ---> a/b
+					parentPath = pathBeforeLastSlash(pathBeforeLastSlash(file.Name))
+				} else {
+					parentPath = pathBeforeLastSlash(file.Name)
+				}
+				populateNewPyPkgs(parentPath, existingPyPkgSet, &newPyPkgs)
+			}
+		}
+		for _, pkg := range newPyPkgs {
+			var emptyBuf []byte
+			fh := &zip.FileHeader{
+				Name:               filepath.Join(pkg, "__init__.py"),
+				Method:             zip.Store,
+				UncompressedSize64: uint64(len(emptyBuf)),
+			}
+			fh.SetMode(0700)
+			fh.SetModTime(jar.DefaultTime)
+			fileSource := bufferEntry{fh, emptyBuf}
+			addMapping(filepath.Join(pkg, "__init__.py"), fileSource)
+		}
+	}
 	for _, namedReader := range readers {
 		_, skipStripThisZip := zipsToNotStrip[namedReader.path]
 		for _, file := range namedReader.reader.File {
@@ -305,6 +375,29 @@
 	return nil
 }
 
+// Sets the given directory and all its ancestor directories as Python packages.
+func populateNewPyPkgs(pkgPath string, existingPyPkgSet map[string]bool, newPyPkgs *[]string) {
+	for pkgPath != "" {
+		if _, found := existingPyPkgSet[pkgPath]; !found {
+			existingPyPkgSet[pkgPath] = true
+			*newPyPkgs = append(*newPyPkgs, pkgPath)
+			// Gets its ancestor directory by trimming last slash.
+			pkgPath = pathBeforeLastSlash(pkgPath)
+		} else {
+			break
+		}
+	}
+}
+
+func pathBeforeLastSlash(path string) string {
+	ret := filepath.Dir(path)
+	// filepath.Dir("abc") -> "." and filepath.Dir("/abc") -> "/".
+	if ret == "." || ret == "/" {
+		return ""
+	}
+	return ret
+}
+
 func shouldStripFile(emulateJar bool, name string) bool {
 	for _, dir := range stripDirs {
 		if strings.HasPrefix(name, dir+"/") {
diff --git a/java/androidmk.go b/java/androidmk.go
index 40ebe5b..24fe43a 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -156,6 +156,12 @@
 				if app.dexJarFile != nil {
 					fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", app.dexJarFile.String())
 				}
+				if app.implementationJarFile != nil {
+					fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", app.implementationJarFile)
+				}
+				if app.headerJarFile != nil {
+					fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", app.headerJarFile.String())
+				}
 				if app.jacocoReportClassesFile != nil {
 					fmt.Fprintln(w, "LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR :=", app.jacocoReportClassesFile.String())
 				}
diff --git a/java/builder.go b/java/builder.go
index 10dfe06..56c7b33 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -200,8 +200,9 @@
 	kotlincFlags     string
 	kotlincClasspath classpath
 
-	protoFlags   []string
-	protoOutFlag string
+	protoFlags       []string
+	protoOutTypeFlag string // The flag itself: --java_out
+	protoOutParams   string // Parameters to that flag: --java_out=$protoOutParams:$outDir
 }
 
 func TransformKotlinToClasses(ctx android.ModuleContext, outputFile android.WritablePath,
@@ -213,11 +214,15 @@
 	inputs := append(android.Paths(nil), srcFiles...)
 	inputs = append(inputs, srcJars...)
 
+	var deps android.Paths
+	deps = append(deps, flags.kotlincClasspath...)
+
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        kotlinc,
 		Description: "kotlinc",
 		Output:      outputFile,
 		Inputs:      inputs,
+		Implicits:   deps,
 		Args: map[string]string{
 			"classpath":    flags.kotlincClasspath.FormJavaClassPath("-classpath"),
 			"kotlincFlags": flags.kotlincFlags,
@@ -378,6 +383,10 @@
 		}
 	}
 
+	// Remove any module-info.class files that may have come from prebuilt jars, they cause problems
+	// for downstream tools like desugar.
+	jarArgs = append(jarArgs, "-stripFile module-info.class")
+
 	if stripDirs {
 		jarArgs = append(jarArgs, "-D")
 	}
@@ -436,7 +445,7 @@
 
 	rule := dx
 	desc := "dx"
-	if ctx.AConfig().IsEnvTrue("USE_D8_DESUGAR") {
+	if ctx.Config().UseD8Desugar() {
 		rule = d8
 		desc = "d8"
 	}
diff --git a/java/config/makevars.go b/java/config/makevars.go
index 5c8589e..c382cc1 100644
--- a/java/config/makevars.go
+++ b/java/config/makevars.go
@@ -46,12 +46,14 @@
 	ctx.Strict("JAVADOC", "${JavadocCmd}")
 	ctx.Strict("COMMON_JDK_FLAGS", "${CommonJdkFlags}")
 
-	if ctx.Config().IsEnvTrue("USE_D8_DESUGAR") {
+	if ctx.Config().UseD8Desugar() {
 		ctx.Strict("DX", "${D8Cmd}")
 		ctx.Strict("DX_COMMAND", "${D8Cmd} -JXms16M -JXmx2048M")
+		ctx.Strict("USE_D8_DESUGAR", "true")
 	} else {
 		ctx.Strict("DX", "${DxCmd}")
 		ctx.Strict("DX_COMMAND", "${DxCmd} -JXms16M -JXmx2048M")
+		ctx.Strict("USE_D8_DESUGAR", "false")
 	}
 
 	ctx.Strict("TURBINE", "${TurbineJar}")
diff --git a/java/gen.go b/java/gen.go
index 7a0dcac..4893e88 100644
--- a/java/gen.go
+++ b/java/gen.go
@@ -107,7 +107,7 @@
 	if len(protoFiles) > 0 {
 		protoSrcJar := android.PathForModuleGen(ctx, "proto.srcjar")
 		genProto(ctx, protoSrcJar, protoFiles,
-			flags.protoFlags, flags.protoOutFlag, "")
+			flags.protoFlags, flags.protoOutTypeFlag, flags.protoOutParams)
 
 		outSrcFiles = append(outSrcFiles, protoSrcJar)
 	}
diff --git a/java/jacoco.go b/java/jacoco.go
index b26b046..59f2fd3 100644
--- a/java/jacoco.go
+++ b/java/jacoco.go
@@ -17,6 +17,7 @@
 // Rules for instrumenting classes using jacoco
 
 import (
+	"fmt"
 	"strings"
 
 	"github.com/google/blueprint"
@@ -59,41 +60,51 @@
 	})
 }
 
-func (j *Module) jacocoStripSpecs(ctx android.ModuleContext) string {
-	includes := jacocoFiltersToSpecs(ctx,
-		j.properties.Jacoco.Include_filter, "jacoco.include_filter")
-	excludes := jacocoFiltersToSpecs(ctx,
-		j.properties.Jacoco.Exclude_filter, "jacoco.exclude_filter")
-
-	specs := ""
-	if len(excludes) > 0 {
-		specs += android.JoinWithPrefix(excludes, "-x") + " "
+func (j *Module) jacocoModuleToZipCommand(ctx android.ModuleContext) string {
+	includes, err := jacocoFiltersToSpecs(j.properties.Jacoco.Include_filter)
+	if err != nil {
+		ctx.PropertyErrorf("jacoco.include_filter", "%s", err.Error())
+	}
+	excludes, err := jacocoFiltersToSpecs(j.properties.Jacoco.Exclude_filter)
+	if err != nil {
+		ctx.PropertyErrorf("jacoco.exclude_filter", "%s", err.Error())
 	}
 
+	return jacocoFiltersToZipCommand(includes, excludes)
+}
+
+func jacocoFiltersToZipCommand(includes, excludes []string) string {
+	specs := ""
+	if len(excludes) > 0 {
+		specs += android.JoinWithPrefix(excludes, "-x ") + " "
+	}
 	if len(includes) > 0 {
 		specs += strings.Join(includes, " ")
 	} else {
 		specs += "**/*.class"
 	}
-
 	return specs
 }
 
-func jacocoFiltersToSpecs(ctx android.ModuleContext, filters []string, property string) []string {
+func jacocoFiltersToSpecs(filters []string) ([]string, error) {
 	specs := make([]string, len(filters))
+	var err error
 	for i, f := range filters {
-		specs[i] = jacocoFilterToSpec(ctx, f, property)
+		specs[i], err = jacocoFilterToSpec(f)
+		if err != nil {
+			return nil, err
+		}
 	}
-	return specs
+	return specs, nil
 }
 
-func jacocoFilterToSpec(ctx android.ModuleContext, filter string, property string) string {
+func jacocoFilterToSpec(filter string) (string, error) {
 	wildcard := strings.HasSuffix(filter, "*")
 	filter = strings.TrimSuffix(filter, "*")
 	recursiveWildcard := wildcard && (strings.HasSuffix(filter, ".") || filter == "")
 
 	if strings.ContainsRune(filter, '*') {
-		ctx.PropertyErrorf(property, "'*' is only supported as the last character in a filter")
+		return "", fmt.Errorf("'*' is only supported as the last character in a filter")
 	}
 
 	spec := strings.Replace(filter, ".", "/", -1)
@@ -102,7 +113,9 @@
 		spec += "**/*.class"
 	} else if wildcard {
 		spec += "*.class"
+	} else {
+		spec += ".class"
 	}
 
-	return spec
+	return spec, nil
 }
diff --git a/java/jacoco_test.go b/java/jacoco_test.go
new file mode 100644
index 0000000..6e8b026
--- /dev/null
+++ b/java/jacoco_test.go
@@ -0,0 +1,95 @@
+// Copyright 2017 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 java
+
+import "testing"
+
+func TestJacocoFilterToSpecs(t *testing.T) {
+	testCases := []struct {
+		name, in, out string
+	}{
+		{
+			name: "class",
+			in:   "package.Class",
+			out:  "package/Class.class",
+		},
+		{
+			name: "class wildcard",
+			in:   "package.Class*",
+			out:  "package/Class*.class",
+		},
+		{
+			name: "package wildcard",
+			in:   "package.*",
+			out:  "package/**/*.class",
+		},
+		{
+			name: "all wildcard",
+			in:   "*",
+			out:  "**/*.class",
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+			got, err := jacocoFilterToSpec(testCase.in)
+			if err != nil {
+				t.Error(err)
+			}
+			if got != testCase.out {
+				t.Errorf("expected %q got %q", testCase.out, got)
+			}
+		})
+	}
+}
+
+func TestJacocoFiltersToZipCommand(t *testing.T) {
+	testCases := []struct {
+		name               string
+		includes, excludes []string
+		out                string
+	}{
+		{
+			name:     "implicit wildcard",
+			includes: []string{},
+			out:      "**/*.class",
+		},
+		{
+			name:     "only include",
+			includes: []string{"package/Class.class"},
+			out:      "package/Class.class",
+		},
+		{
+			name:     "multiple includes",
+			includes: []string{"package/Class.class", "package2/Class.class"},
+			out:      "package/Class.class package2/Class.class",
+		},
+		{
+			name:     "excludes",
+			includes: []string{"package/**/*.class"},
+			excludes: []string{"package/Class.class"},
+			out:      "-x package/Class.class package/**/*.class",
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+			got := jacocoFiltersToZipCommand(testCase.includes, testCase.excludes)
+			if got != testCase.out {
+				t.Errorf("expected %q got %q", testCase.out, got)
+			}
+		})
+	}
+}
diff --git a/java/java.go b/java/java.go
index d9075b1..dbf202a 100644
--- a/java/java.go
+++ b/java/java.go
@@ -142,6 +142,11 @@
 		Exclude_filter []string
 	}
 
+	Proto struct {
+		// List of extra options that will be passed to the proto generator.
+		Output_params []string
+	}
+
 	Instrument bool `blueprint:"mutated"`
 }
 
@@ -620,7 +625,7 @@
 	}
 	srcFiles := ctx.ExpandSources(j.properties.Srcs, j.properties.Exclude_srcs)
 	if hasSrcExt(srcFiles.Strings(), ".proto") {
-		flags = protoFlags(ctx, &j.protoProperties, flags)
+		flags = protoFlags(ctx, &j.properties, &j.protoProperties, flags)
 	}
 
 	srcFiles = j.genSources(ctx, srcFiles, flags)
@@ -672,7 +677,7 @@
 	// Store the list of .java files that was passed to javac
 	j.compiledJavaSrcs = uniqueSrcFiles
 	j.compiledSrcJars = srcJars
-	fullD8 := ctx.AConfig().IsEnvTrue("USE_D8_DESUGAR")
+	fullD8 := ctx.Config().UseD8Desugar()
 
 	enable_sharding := false
 	if ctx.Device() && !ctx.Config().IsEnvFalse("TURBINE_ENABLED") {
@@ -776,6 +781,9 @@
 
 	if len(jars) == 1 && !manifest.Valid() {
 		// Optimization: skip the combine step if there is nothing to do
+		// TODO(ccross): this leaves any module-info.class files, but those should only come from
+		// prebuilt dependencies until we support modules in the platform build, so there shouldn't be
+		// any if len(jars) == 1.
 		outputFile = jars[0]
 	} else {
 		combinedJar := android.PathForModuleOut(ctx, "combined", jarName)
@@ -889,7 +897,7 @@
 func (j *Module) instrument(ctx android.ModuleContext, flags javaBuilderFlags,
 	classesJar android.Path, jarName string) android.Path {
 
-	specs := j.jacocoStripSpecs(ctx)
+	specs := j.jacocoModuleToZipCommand(ctx)
 
 	jacocoReportClassesFile := android.PathForModuleOut(ctx, "jacoco", "jacoco-report-classes.jar")
 	instrumentedJar := android.PathForModuleOut(ctx, "jacoco", jarName)
@@ -937,20 +945,12 @@
 	// to D8 flags. See: b/69377755
 	var dxFlags []string
 	for _, x := range j.deviceProperties.Dxflags {
-		if x == "--core-library" {
+		switch x {
+		case "--core-library", "--dex", "--multi-dex":
 			continue
+		default:
+			dxFlags = append(dxFlags, x)
 		}
-		if x == "--dex" {
-			continue
-		}
-		if x == "--multi-dex" {
-			continue
-		}
-		if x == "--no-locals" {
-			dxFlags = append(dxFlags, "--release")
-			continue
-		}
-		dxFlags = append(dxFlags, x)
 	}
 
 	if ctx.AConfig().Getenv("NO_OPTIMIZE_DX") != "" {
diff --git a/java/java_test.go b/java/java_test.go
index 78fbd41..84fe903 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -705,43 +705,61 @@
 	ctx := testJava(t, `
 		java_library {
 			name: "foo",
-                        srcs: ["a.java", "b.kt"],
+			srcs: ["a.java", "b.kt"],
 		}
 
 		java_library {
 			name: "bar",
-                        srcs: ["b.kt"],
+			srcs: ["b.kt"],
+			libs: ["foo"],
+			static_libs: ["baz"],
+		}
+
+		java_library {
+			name: "baz",
+			srcs: ["c.java"],
 		}
 		`)
 
-	kotlinc := ctx.ModuleForTests("foo", "android_common").Rule("kotlinc")
-	javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
-	jar := ctx.ModuleForTests("foo", "android_common").Output("combined/foo.jar")
+	fooKotlinc := ctx.ModuleForTests("foo", "android_common").Rule("kotlinc")
+	fooJavac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
+	fooJar := ctx.ModuleForTests("foo", "android_common").Output("combined/foo.jar")
 
-	if len(kotlinc.Inputs) != 2 || kotlinc.Inputs[0].String() != "a.java" ||
-		kotlinc.Inputs[1].String() != "b.kt" {
-		t.Errorf(`foo kotlinc inputs %v != ["a.java", "b.kt"]`, kotlinc.Inputs)
+	if len(fooKotlinc.Inputs) != 2 || fooKotlinc.Inputs[0].String() != "a.java" ||
+		fooKotlinc.Inputs[1].String() != "b.kt" {
+		t.Errorf(`foo kotlinc inputs %v != ["a.java", "b.kt"]`, fooKotlinc.Inputs)
 	}
 
-	if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" {
-		t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs)
+	if len(fooJavac.Inputs) != 1 || fooJavac.Inputs[0].String() != "a.java" {
+		t.Errorf(`foo inputs %v != ["a.java"]`, fooJavac.Inputs)
 	}
 
-	if !strings.Contains(javac.Args["classpath"], kotlinc.Output.String()) {
+	if !strings.Contains(fooJavac.Args["classpath"], fooKotlinc.Output.String()) {
 		t.Errorf("foo classpath %v does not contain %q",
-			javac.Args["classpath"], kotlinc.Output.String())
+			fooJavac.Args["classpath"], fooKotlinc.Output.String())
 	}
 
-	if !inList(kotlinc.Output.String(), jar.Inputs.Strings()) {
+	if !inList(fooKotlinc.Output.String(), fooJar.Inputs.Strings()) {
 		t.Errorf("foo jar inputs %v does not contain %q",
-			jar.Inputs.Strings(), kotlinc.Output.String())
+			fooJar.Inputs.Strings(), fooKotlinc.Output.String())
 	}
 
-	kotlinc = ctx.ModuleForTests("bar", "android_common").Rule("kotlinc")
-	jar = ctx.ModuleForTests("bar", "android_common").Output("combined/bar.jar")
+	fooHeaderJar := ctx.ModuleForTests("foo", "android_common").Output("turbine-combined/foo.jar")
+	bazHeaderJar := ctx.ModuleForTests("baz", "android_common").Output("turbine-combined/baz.jar")
+	barKotlinc := ctx.ModuleForTests("bar", "android_common").Rule("kotlinc")
 
-	if len(kotlinc.Inputs) != 1 || kotlinc.Inputs[0].String() != "b.kt" {
-		t.Errorf(`bar kotlinc inputs %v != ["b.kt"]`, kotlinc.Inputs)
+	if len(barKotlinc.Inputs) != 1 || barKotlinc.Inputs[0].String() != "b.kt" {
+		t.Errorf(`bar kotlinc inputs %v != ["b.kt"]`, barKotlinc.Inputs)
+	}
+
+	if !inList(fooHeaderJar.Output.String(), barKotlinc.Implicits.Strings()) {
+		t.Errorf(`expected %q in bar implicits %v`,
+			fooHeaderJar.Output.String(), barKotlinc.Implicits.Strings())
+	}
+
+	if !inList(bazHeaderJar.Output.String(), barKotlinc.Implicits.Strings()) {
+		t.Errorf(`expected %q in bar implicits %v`,
+			bazHeaderJar.Output.String(), barKotlinc.Implicits.Strings())
 	}
 }
 
@@ -754,7 +772,7 @@
 
 		java_library {
 			name: "bar",
-                        srcs: ["b.java"],
+			srcs: ["b.java"],
 			static_libs: ["foo"],
 		}
 
diff --git a/java/proto.go b/java/proto.go
index 17f02a3..226fac0 100644
--- a/java/proto.go
+++ b/java/proto.go
@@ -31,17 +31,17 @@
 	proto = pctx.AndroidStaticRule("protoc",
 		blueprint.RuleParams{
 			Command: `rm -rf $outDir && mkdir -p $outDir && ` +
-				`$protocCmd $protoOut=$protoOutFlags:$outDir $protoFlags $in && ` +
+				`$protocCmd $protoOut=$protoOutParams:$outDir $protoFlags $in && ` +
 				`${config.SoongZipCmd} -jar -o $out -C $outDir -D $outDir`,
 			CommandDeps: []string{
 				"$protocCmd",
 				"${config.SoongZipCmd}",
 			},
-		}, "protoFlags", "protoOut", "protoOutFlags", "outDir")
+		}, "protoFlags", "protoOut", "protoOutParams", "outDir")
 )
 
 func genProto(ctx android.ModuleContext, outputSrcJar android.WritablePath,
-	protoFiles android.Paths, protoFlags []string, protoOut, protoOutFlags string) {
+	protoFiles android.Paths, protoFlags []string, protoOut, protoOutParams string) {
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        proto,
@@ -49,10 +49,10 @@
 		Output:      outputSrcJar,
 		Inputs:      protoFiles,
 		Args: map[string]string{
-			"outDir":        android.ProtoDir(ctx).String(),
-			"protoOut":      protoOut,
-			"protoOutFlags": protoOutFlags,
-			"protoFlags":    strings.Join(protoFlags, " "),
+			"outDir":         android.ProtoDir(ctx).String(),
+			"protoOut":       protoOut,
+			"protoOutParams": protoOutParams,
+			"protoFlags":     strings.Join(protoFlags, " "),
 		},
 	})
 }
@@ -77,19 +77,31 @@
 	}
 }
 
-func protoFlags(ctx android.ModuleContext, p *android.ProtoProperties, flags javaBuilderFlags) javaBuilderFlags {
+func protoFlags(ctx android.ModuleContext, j *CompilerProperties, p *android.ProtoProperties,
+	flags javaBuilderFlags) javaBuilderFlags {
+
 	switch proptools.String(p.Proto.Type) {
 	case "micro":
-		flags.protoOutFlag = "--javamicro_out"
+		flags.protoOutTypeFlag = "--javamicro_out"
 	case "nano":
-		flags.protoOutFlag = "--javanano_out"
-	case "lite", "full", "":
-		flags.protoOutFlag = "--java_out"
+		flags.protoOutTypeFlag = "--javanano_out"
+	case "lite":
+		flags.protoOutTypeFlag = "--java_out"
+		flags.protoOutParams = "lite"
+	case "full", "":
+		flags.protoOutTypeFlag = "--java_out"
 	default:
 		ctx.PropertyErrorf("proto.type", "unknown proto type %q",
 			proptools.String(p.Proto.Type))
 	}
 
+	if len(j.Proto.Output_params) > 0 {
+		if flags.protoOutParams != "" {
+			flags.protoOutParams += ","
+		}
+		flags.protoOutParams += strings.Join(j.Proto.Output_params, ",")
+	}
+
 	flags.protoFlags = android.ProtoFlags(ctx, p)
 
 	return flags
diff --git a/ui/build/config.go b/ui/build/config.go
index df97d80..c975243 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -146,14 +146,16 @@
 	}
 
 	// Configure Java-related variables, including adding it to $PATH
+	java8Home := filepath.Join("prebuilts/jdk/jdk8", ret.HostPrebuiltTag())
+	java9Home := filepath.Join("prebuilts/jdk/jdk9", ret.HostPrebuiltTag())
 	javaHome := func() string {
 		if override, ok := ret.environ.Get("OVERRIDE_ANDROID_JAVA_HOME"); ok {
 			return override
 		}
 		if v, ok := ret.environ.Get("EXPERIMENTAL_USE_OPENJDK9"); ok && v != "" && v != "false" {
-			return filepath.Join("prebuilts/jdk/jdk9", ret.HostPrebuiltTag())
+			return java9Home
 		}
-		return filepath.Join("prebuilts/jdk/jdk8", ret.HostPrebuiltTag())
+		return java8Home
 	}()
 	absJavaHome := absPath(ctx, javaHome)
 
@@ -164,6 +166,8 @@
 	ret.environ.Unset("OVERRIDE_ANDROID_JAVA_HOME")
 	ret.environ.Set("JAVA_HOME", absJavaHome)
 	ret.environ.Set("ANDROID_JAVA_HOME", javaHome)
+	ret.environ.Set("ANDROID_JAVA8_HOME", java8Home)
+	ret.environ.Set("ANDROID_JAVA9_HOME", java9Home)
 	ret.environ.Set("PATH", strings.Join(newPath, string(filepath.ListSeparator)))
 
 	return Config{ret}