Merge "Disable dtor inlining for clang-tidy"
diff --git a/Android.bp b/Android.bp
index 4a06a11..2daa958 100644
--- a/Android.bp
+++ b/Android.bp
@@ -233,8 +233,10 @@
         "java/jacoco.go",
         "java/java.go",
         "java/java_resources.go",
+        "java/prebuilt_apis.go",
         "java/proto.go",
         "java/sdk_library.go",
+        "java/support_libraries.go",
         "java/system_modules.go",
     ],
     testSrcs: [
@@ -334,6 +336,7 @@
     name: "libatomic",
     defaults: ["linux_bionic_supported"],
     vendor_available: true,
+    recovery_available: true,
     arch: {
         arm: {
             instruction_set: "arm",
@@ -345,6 +348,7 @@
     name: "libgcc",
     defaults: ["linux_bionic_supported"],
     vendor_available: true,
+    recovery_available: true,
     arch: {
         arm: {
             instruction_set: "arm",
diff --git a/android/arch.go b/android/arch.go
index 9f03f1b..ebe9897 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -956,6 +956,7 @@
 		{"arm", "armv7-a-neon", "cortex-a53", []string{"armeabi-v7a"}},
 		{"arm", "armv7-a-neon", "cortex-a53.a57", []string{"armeabi-v7a"}},
 		{"arm", "armv7-a-neon", "cortex-a73", []string{"armeabi-v7a"}},
+		{"arm", "armv7-a-neon", "cortex-a75", []string{"armeabi-v7a"}},
 		{"arm", "armv7-a-neon", "denver", []string{"armeabi-v7a"}},
 		{"arm", "armv7-a-neon", "krait", []string{"armeabi-v7a"}},
 		{"arm", "armv7-a-neon", "kryo", []string{"armeabi-v7a"}},
@@ -967,6 +968,7 @@
 		{"arm64", "armv8-a", "kryo", []string{"arm64-v8a"}},
 		{"arm64", "armv8-a", "exynos-m1", []string{"arm64-v8a"}},
 		{"arm64", "armv8-a", "exynos-m2", []string{"arm64-v8a"}},
+		{"arm64", "armv8-2a", "cortex-a75", []string{"arm64-v8a"}},
 		{"mips", "mips32-fp", "", []string{"mips"}},
 		{"mips", "mips32r2-fp", "", []string{"mips"}},
 		{"mips", "mips32r2-fp-xburst", "", []string{"mips"}},
diff --git a/android/config.go b/android/config.go
index 40ba8c1..7f2a3ac 100644
--- a/android/config.go
+++ b/android/config.go
@@ -468,6 +468,10 @@
 	return *c.productVariables.ResourceOverlays
 }
 
+func (c *config) PlatformVersionName() string {
+	return String(c.productVariables.Platform_version_name)
+}
+
 func (c *config) PlatformSdkVersionInt() int {
 	return *c.productVariables.Platform_sdk_version
 }
@@ -799,6 +803,22 @@
 	return c.config.productVariables.PgoAdditionalProfileDirs
 }
 
+func (c *deviceConfig) VendorSepolicyDirs() []string {
+	return c.config.productVariables.BoardVendorSepolicyDirs
+}
+
+func (c *deviceConfig) OdmSepolicyDirs() []string {
+	return c.config.productVariables.BoardOdmSepolicyDirs
+}
+
+func (c *deviceConfig) PlatPublicSepolicyDir() string {
+	return c.config.productVariables.BoardPlatPublicSepolicyDir
+}
+
+func (c *deviceConfig) PlatPrivateSepolicyDir() string {
+	return c.config.productVariables.BoardPlatPrivateSepolicyDir
+}
+
 func (c *config) IntegerOverflowDisabledForPath(path string) bool {
 	if c.productVariables.IntegerOverflowExcludePaths == nil {
 		return false
diff --git a/android/module.go b/android/module.go
index 552d165..3316a44 100644
--- a/android/module.go
+++ b/android/module.go
@@ -124,6 +124,7 @@
 
 	InstallInData() bool
 	InstallInSanitizerDir() bool
+	InstallInRecovery() bool
 
 	RequiredModuleNames() []string
 
@@ -176,6 +177,7 @@
 	Target() Target
 	InstallInData() bool
 	InstallInSanitizerDir() bool
+	InstallInRecovery() bool
 	SkipInstall()
 	ExportedToMake() bool
 
@@ -191,8 +193,6 @@
 }
 
 type commonProperties struct {
-	Tags []string
-
 	// emit build rules for this module
 	Enabled *bool `android:"arch_variant"`
 
@@ -239,6 +239,9 @@
 	// /system/product if product partition does not exist).
 	Product_specific *bool
 
+	// Whether this module is installed to recovery partition
+	Recovery *bool
+
 	// init.rc files to be installed if this module is installed
 	Init_rc []string
 
@@ -562,6 +565,10 @@
 	return false
 }
 
+func (p *ModuleBase) InstallInRecovery() bool {
+	return Bool(p.commonProperties.Recovery)
+}
+
 func (a *ModuleBase) generateModuleTarget(ctx ModuleContext) {
 	allInstalledFiles := Paths{}
 	allCheckbuildFiles := Paths{}
@@ -1010,11 +1017,22 @@
 	return a.module.InstallInSanitizerDir()
 }
 
+func (a *androidModuleContext) InstallInRecovery() bool {
+	return a.module.InstallInRecovery()
+}
+
 func (a *androidModuleContext) skipInstall(fullInstallPath OutputPath) bool {
 	if a.module.base().commonProperties.SkipInstall {
 		return true
 	}
 
+	// We'll need a solution for choosing which of modules with the same name in different
+	// namespaces to install.  For now, reuse the list of namespaces exported to Make as the
+	// list of namespaces to install in a Soong-only build.
+	if !a.module.base().commonProperties.NamespaceExportedToMake {
+		return true
+	}
+
 	if a.Device() {
 		if a.Config().SkipDeviceInstall() {
 			return true
diff --git a/android/paths.go b/android/paths.go
index 91dd9a6..8cc3182 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -47,6 +47,7 @@
 
 	InstallInData() bool
 	InstallInSanitizerDir() bool
+	InstallInRecovery() bool
 }
 
 var _ ModuleInstallPathContext = ModuleContext(nil)
@@ -948,6 +949,8 @@
 		var partition string
 		if ctx.InstallInData() {
 			partition = "data"
+		} else if ctx.InstallInRecovery() {
+			partition = "recovery/root"
 		} else if ctx.SocSpecific() {
 			partition = ctx.DeviceConfig().VendorPath()
 		} else if ctx.DeviceSpecific() {
diff --git a/android/paths_test.go b/android/paths_test.go
index cd9fbfd..b3dc9de 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -201,6 +201,7 @@
 
 	inData         bool
 	inSanitizerDir bool
+	inRecovery     bool
 }
 
 func (moduleInstallPathContextImpl) Fs() pathtools.FileSystem {
@@ -221,6 +222,10 @@
 	return m.inSanitizerDir
 }
 
+func (m moduleInstallPathContextImpl) InstallInRecovery() bool {
+	return m.inRecovery
+}
+
 func TestPathForModuleInstall(t *testing.T) {
 	testConfig := TestConfig("", nil)
 
diff --git a/android/variable.go b/android/variable.go
index 2057903..6599ca3 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -109,6 +109,7 @@
 	BuildNumberFromFile *string `json:",omitempty"`
 	DateFromFile        *string `json:",omitempty"`
 
+	Platform_version_name             *string  `json:",omitempty"`
 	Platform_sdk_version              *int     `json:",omitempty"`
 	Platform_sdk_codename             *string  `json:",omitempty"`
 	Platform_sdk_final                *bool    `json:",omitempty"`
@@ -209,6 +210,11 @@
 
 	PgoAdditionalProfileDirs []string `json:",omitempty"`
 
+	BoardVendorSepolicyDirs     []string `json:",omitempty"`
+	BoardOdmSepolicyDirs        []string `json:",omitempty"`
+	BoardPlatPublicSepolicyDir  string   `json:",omitempty"`
+	BoardPlatPrivateSepolicyDir string   `json:",omitempty"`
+
 	VendorVars map[string]map[string]string `json:",omitempty"`
 }
 
diff --git a/androidmk/Android.bp b/androidmk/Android.bp
index 442452f..1d939b0 100644
--- a/androidmk/Android.bp
+++ b/androidmk/Android.bp
@@ -44,6 +44,6 @@
     ],
     testSrcs: [
         "parser/make_strings_test.go",
+        "parser/parser_test.go",
     ],
 }
-
diff --git a/androidmk/cmd/androidmk/androidmk_test.go b/androidmk/cmd/androidmk/androidmk_test.go
index edf3d42..a54a4d2 100644
--- a/androidmk/cmd/androidmk/androidmk_test.go
+++ b/androidmk/cmd/androidmk/androidmk_test.go
@@ -331,7 +331,7 @@
 `,
 	},
 	{
-		desc: "Keep LOCAL_MODULE_TAGS non-optional",
+		desc: "Warn for LOCAL_MODULE_TAGS non-optional",
 		in: `
 include $(CLEAR_VARS)
 LOCAL_MODULE_TAGS := debug
@@ -340,7 +340,41 @@
 
 		expected: `
 cc_library_shared {
-	tags: ["debug"],
+	// WARNING: Module tags are not supported in Soong.
+	// Add this module to PRODUCT_PACKAGES_DEBUG in your product file if you want to
+	// force installation for -userdebug and -eng builds.
+}
+`,
+	},
+	{
+		desc: "Custom warning for LOCAL_MODULE_TAGS tests",
+		in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := debug tests
+include $(BUILD_SHARED_LIBRARY)
+`,
+
+		expected: `
+cc_library_shared {
+	// WARNING: Module tags are not supported in Soong.
+	// Add this module to PRODUCT_PACKAGES_DEBUG in your product file if you want to
+	// force installation for -userdebug and -eng builds.
+	// WARNING: Module tags are not supported in Soong.
+	// To make a shared library only for tests, use the "cc_test_library" module
+	// type. If you don't use gtest, set "gtest: false".
+}
+`,
+	},
+	{
+		desc: "Ignore LOCAL_MODULE_TAGS tests for cc_test",
+		in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+include $(BUILD_NATIVE_TEST)
+`,
+
+		expected: `
+cc_test {
 }
 `,
 	},
@@ -576,6 +610,19 @@
 			}
 		`,
 	},
+	{
+		desc: "cc_library shared_libs",
+		in: `
+			include $(CLEAR_VARS)
+			LOCAL_SHARED_LIBRARIES := libfoo
+			include $(BUILD_SHARED_LIBRARY)
+		`,
+		expected: `
+			cc_library_shared {
+				shared_libs: ["libfoo"],
+			}
+		`,
+	},
 }
 
 func TestEndToEnd(t *testing.T) {
diff --git a/androidmk/parser/make_strings.go b/androidmk/parser/make_strings.go
index e6885a8..4b782a2 100644
--- a/androidmk/parser/make_strings.go
+++ b/androidmk/parser/make_strings.go
@@ -90,10 +90,10 @@
 	if len(ms.Strings) == 0 {
 		return ""
 	} else {
-		ret := ms.Strings[0]
+		ret := unescape(ms.Strings[0])
 		for i := range ms.Strings[1:] {
 			ret += ms.Variables[i].Value(scope)
-			ret += ms.Strings[i+1]
+			ret += unescape(ms.Strings[i+1])
 		}
 		return ret
 	}
@@ -125,6 +125,16 @@
 }
 
 func (ms *MakeString) SplitN(sep string, n int) []*MakeString {
+	return ms.splitNFunc(n, func(s string, n int) []string {
+		return splitAnyN(s, sep, n)
+	})
+}
+
+func (ms *MakeString) Words() []*MakeString {
+	return ms.splitNFunc(-1, splitWords)
+}
+
+func (ms *MakeString) splitNFunc(n int, splitFunc func(s string, n int) []string) []*MakeString {
 	ret := []*MakeString{}
 
 	curMs := SimpleMakeString("", ms.Pos())
@@ -133,7 +143,7 @@
 	var s string
 	for i, s = range ms.Strings {
 		if n != 0 {
-			split := splitAnyN(s, sep, n)
+			split := splitFunc(s, n)
 			if n != -1 {
 				if len(split) > n {
 					panic("oops!")
@@ -156,7 +166,9 @@
 		}
 	}
 
-	ret = append(ret, curMs)
+	if !curMs.Empty() {
+		ret = append(ret, curMs)
+	}
 	return ret
 }
 
@@ -206,3 +218,64 @@
 	ret = append(ret, s)
 	return ret
 }
+
+func splitWords(s string, n int) []string {
+	ret := []string{}
+	preserve := ""
+	for n == -1 || n > 1 {
+		index := strings.IndexAny(s, " \t")
+		if index == 0 && len(preserve) == 0 {
+			s = s[1:]
+		} else if index >= 0 {
+			escapeCount := 0
+			for i := index - 1; i >= 0; i-- {
+				if s[i] != '\\' {
+					break
+				}
+				escapeCount += 1
+			}
+
+			if escapeCount%2 == 1 {
+				preserve += s[0 : index+1]
+				s = s[index+1:]
+				continue
+			}
+
+			ret = append(ret, preserve+s[0:index])
+			s = s[index+1:]
+			preserve = ""
+			if n > 0 {
+				n--
+			}
+		} else {
+			break
+		}
+	}
+	if preserve != "" || s != "" || len(ret) == 0 {
+		ret = append(ret, preserve+s)
+	}
+	return ret
+}
+
+func unescape(s string) string {
+	ret := ""
+	for {
+		index := strings.IndexByte(s, '\\')
+		if index < 0 {
+			break
+		}
+
+		if index+1 == len(s) {
+			break
+		}
+
+		switch s[index+1] {
+		case ' ', '\\', '#', ':', '*', '[', '|', '\t', '\n', '\r':
+			ret += s[:index] + s[index+1:index+2]
+		default:
+			ret += s[:index+2]
+		}
+		s = s[index+2:]
+	}
+	return ret + s
+}
diff --git a/androidmk/parser/make_strings_test.go b/androidmk/parser/make_strings_test.go
index 8ad3d74..6995e89 100644
--- a/androidmk/parser/make_strings_test.go
+++ b/androidmk/parser/make_strings_test.go
@@ -99,6 +99,78 @@
 	}
 }
 
+var valueTestCases = []struct {
+	in       *MakeString
+	expected string
+}{
+	{
+		in:       SimpleMakeString("a b", NoPos),
+		expected: "a b",
+	},
+	{
+		in:       SimpleMakeString("a\\ \\\tb\\\\", NoPos),
+		expected: "a \tb\\",
+	},
+	{
+		in:       SimpleMakeString("a\\b\\", NoPos),
+		expected: "a\\b\\",
+	},
+}
+
+func TestMakeStringValue(t *testing.T) {
+	for _, test := range valueTestCases {
+		got := test.in.Value(nil)
+		if got != test.expected {
+			t.Errorf("\nwith: %q\nwant: %q\n got: %q", test.in.Dump(), test.expected, got)
+		}
+	}
+}
+
+var splitWordsTestCases = []struct {
+	in       *MakeString
+	expected []*MakeString
+}{
+	{
+		in:       SimpleMakeString("", NoPos),
+		expected: []*MakeString{},
+	},
+	{
+		in: SimpleMakeString(" a b\\ c d", NoPos),
+		expected: []*MakeString{
+			SimpleMakeString("a", NoPos),
+			SimpleMakeString("b\\ c", NoPos),
+			SimpleMakeString("d", NoPos),
+		},
+	},
+	{
+		in: SimpleMakeString("  a\tb\\\t\\ c d  ", NoPos),
+		expected: []*MakeString{
+			SimpleMakeString("a", NoPos),
+			SimpleMakeString("b\\\t\\ c", NoPos),
+			SimpleMakeString("d", NoPos),
+		},
+	},
+	{
+		in: SimpleMakeString(`a\\ b\\\ c d`, NoPos),
+		expected: []*MakeString{
+			SimpleMakeString(`a\\`, NoPos),
+			SimpleMakeString(`b\\\ c`, NoPos),
+			SimpleMakeString("d", NoPos),
+		},
+	},
+}
+
+func TestMakeStringWords(t *testing.T) {
+	for _, test := range splitWordsTestCases {
+		got := test.in.Words()
+		gotString := dumpArray(got)
+		expectedString := dumpArray(test.expected)
+		if gotString != expectedString {
+			t.Errorf("with:\n%q\nexpected:\n%s\ngot:\n%s", test.in.Dump(), expectedString, gotString)
+		}
+	}
+}
+
 func dumpArray(a []*MakeString) string {
 	ret := make([]string, len(a))
 
diff --git a/androidmk/parser/parser.go b/androidmk/parser/parser.go
index 89ee308..89c1af9 100644
--- a/androidmk/parser/parser.go
+++ b/androidmk/parser/parser.go
@@ -35,6 +35,10 @@
 	return fmt.Sprintf("%s: %s", e.Pos, e.Err)
 }
 
+const builtinDollar = "__builtin_dollar"
+
+var builtinDollarName = SimpleMakeString(builtinDollar, NoPos)
+
 func (p *parser) Parse() ([]Node, []error) {
 	defer func() {
 		if r := recover(); r != nil {
@@ -326,7 +330,11 @@
 		case '$':
 			var variable Variable
 			variable = p.parseVariable()
-			value.appendVariable(variable)
+			if variable.Name == builtinDollarName {
+				value.appendString("$")
+			} else {
+				value.appendVariable(variable)
+			}
 		case scanner.EOF:
 			break loop
 		case '(':
@@ -357,7 +365,8 @@
 	case '{':
 		return p.parseBracketedVariable('{', '}', pos)
 	case '$':
-		name = SimpleMakeString("__builtin_dollar", NoPos)
+		name = builtinDollarName
+		p.accept(p.tok)
 	case scanner.EOF:
 		p.errorf("expected variable name, found %s",
 			scanner.TokenString(p.tok))
@@ -457,6 +466,8 @@
 	case '=':
 		p.parseAssignment("=", target, prerequisites)
 		return nil, true
+	case scanner.EOF:
+		// do nothing
 	default:
 		p.errorf("unexpected token %s after rule prerequisites", scanner.TokenString(p.tok))
 	}
diff --git a/androidmk/parser/parser_test.go b/androidmk/parser/parser_test.go
new file mode 100644
index 0000000..f562c29
--- /dev/null
+++ b/androidmk/parser/parser_test.go
@@ -0,0 +1,61 @@
+// Copyright 2018 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package parser
+
+import (
+	"bytes"
+	"testing"
+)
+
+var parserTestCases = []struct {
+	name string
+	in   string
+	out  []Node
+}{
+	{
+		name: "Escaped $",
+		in:   `a$$ b: c`,
+		out: []Node{
+			&Rule{
+				Target:        SimpleMakeString("a$ b", NoPos),
+				Prerequisites: SimpleMakeString("c", NoPos),
+			},
+		},
+	},
+}
+
+func TestParse(t *testing.T) {
+	for _, test := range parserTestCases {
+		t.Run(test.name, func(t *testing.T) {
+			p := NewParser(test.name, bytes.NewBufferString(test.in))
+			got, errs := p.Parse()
+
+			if len(errs) != 0 {
+				t.Fatalf("Unexpected errors while parsing: %v", errs)
+			}
+
+			if len(got) != len(test.out) {
+				t.Fatalf("length mismatch, expected %d nodes, got %d", len(test.out), len(got))
+			}
+
+			for i := range got {
+				if got[i].Dump() != test.out[i].Dump() {
+					t.Errorf("incorrect node %d:\nexpected: %#v (%s)\n     got: %#v (%s)",
+						i, test.out[i], test.out[i].Dump(), got[i], got[i].Dump())
+				}
+			}
+		})
+	}
+}
diff --git a/androidmk/parser/scope.go b/androidmk/parser/scope.go
index 7a514fa..167e470 100644
--- a/androidmk/parser/scope.go
+++ b/androidmk/parser/scope.go
@@ -71,7 +71,7 @@
 
 func init() {
 	builtinScope := make(map[string]string)
-	builtinScope["__builtin_dollar"] = "$"
+	builtinScope[builtinDollar] = "$"
 }
 
 func (v Variable) EvalFunction(scope Scope) (string, bool) {
diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go
index e4d4e34..ee00907 100644
--- a/bpfix/bpfix/bpfix.go
+++ b/bpfix/bpfix/bpfix.go
@@ -22,6 +22,7 @@
 	"fmt"
 	"io"
 	"path/filepath"
+	"strings"
 
 	"github.com/google/blueprint/parser"
 )
@@ -48,6 +49,8 @@
 	rewriteIncorrectAndroidmkPrebuilts        bool
 	rewriteIncorrectAndroidmkAndroidLibraries bool
 	mergeMatchingModuleProperties             bool
+	reorderCommonProperties                   bool
+	removeTags                                bool
 }
 
 func NewFixRequest() FixRequest {
@@ -60,6 +63,8 @@
 	result.rewriteIncorrectAndroidmkPrebuilts = true
 	result.rewriteIncorrectAndroidmkAndroidLibraries = true
 	result.mergeMatchingModuleProperties = true
+	result.reorderCommonProperties = true
+	result.removeTags = true
 	return result
 }
 
@@ -144,11 +149,12 @@
 
 func (f *Fixer) fixTreeOnce(config FixRequest) error {
 	if config.simplifyKnownRedundantVariables {
-		err := f.simplifyKnownPropertiesDuplicatingEachOther()
+		err := f.runPatchListMod(simplifyKnownPropertiesDuplicatingEachOther)
 		if err != nil {
 			return err
 		}
 	}
+
 	if config.rewriteIncorrectAndroidmkPrebuilts {
 		err := f.rewriteIncorrectAndroidmkPrebuilts()
 		if err != nil {
@@ -164,7 +170,21 @@
 	}
 
 	if config.mergeMatchingModuleProperties {
-		err := f.mergeMatchingModuleProperties()
+		err := f.runPatchListMod(mergeMatchingModuleProperties)
+		if err != nil {
+			return err
+		}
+	}
+
+	if config.reorderCommonProperties {
+		err := f.runPatchListMod(reorderCommonProperties)
+		if err != nil {
+			return err
+		}
+	}
+
+	if config.removeTags {
+		err := f.runPatchListMod(removeTags)
 		if err != nil {
 			return err
 		}
@@ -172,9 +192,10 @@
 	return nil
 }
 
-func (f *Fixer) simplifyKnownPropertiesDuplicatingEachOther() error {
+func simplifyKnownPropertiesDuplicatingEachOther(mod *parser.Module, buf []byte, patchList *parser.PatchList) error {
 	// remove from local_include_dirs anything in export_include_dirs
-	return f.removeMatchingModuleListProperties("export_include_dirs", "local_include_dirs")
+	return removeMatchingModuleListProperties(mod, patchList,
+		"export_include_dirs", "local_include_dirs")
 }
 
 func (f *Fixer) rewriteIncorrectAndroidmkPrebuilts() error {
@@ -220,6 +241,10 @@
 			continue
 		}
 
+		if !strings.HasPrefix(mod.Type, "java_") && !strings.HasPrefix(mod.Type, "android_") {
+			continue
+		}
+
 		hasAndroidLibraries := hasNonEmptyLiteralListProperty(mod, "android_libs")
 		hasStaticAndroidLibraries := hasNonEmptyLiteralListProperty(mod, "android_static_libs")
 		hasResourceDirs := hasNonEmptyLiteralListProperty(mod, "resource_dirs")
@@ -244,7 +269,7 @@
 	return nil
 }
 
-func (f *Fixer) mergeMatchingModuleProperties() error {
+func (f *Fixer) runPatchListMod(modFunc func(mod *parser.Module, buf []byte, patchlist *parser.PatchList) error) error {
 	// Make sure all the offsets are accurate
 	buf, err := f.reparse()
 	if err != nil {
@@ -258,7 +283,7 @@
 			continue
 		}
 
-		err := mergeMatchingProperties(&mod.Properties, buf, &patchlist)
+		err := modFunc(mod, buf, &patchlist)
 		if err != nil {
 			return err
 		}
@@ -270,9 +295,12 @@
 		return err
 	}
 
+	// Save a copy of the buffer to print for errors below
+	bufCopy := append([]byte(nil), newBuf.Bytes()...)
+
 	newTree, err := parse(f.tree.Name, newBuf)
 	if err != nil {
-		return err
+		return fmt.Errorf("Failed to parse: %v\nBuffer:\n%s", err, string(bufCopy))
 	}
 
 	f.tree = newTree
@@ -280,6 +308,129 @@
 	return nil
 }
 
+var commonPropertyPriorities = []string{
+	"name",
+	"defaults",
+	"device_supported",
+	"host_supported",
+}
+
+func reorderCommonProperties(mod *parser.Module, buf []byte, patchlist *parser.PatchList) error {
+	if len(mod.Properties) == 0 {
+		return nil
+	}
+
+	pos := mod.LBracePos.Offset + 1
+	stage := ""
+
+	for _, name := range commonPropertyPriorities {
+		idx := propertyIndex(mod.Properties, name)
+		if idx == -1 {
+			continue
+		}
+		if idx == 0 {
+			err := patchlist.Add(pos, pos, stage)
+			if err != nil {
+				return err
+			}
+			stage = ""
+
+			pos = mod.Properties[0].End().Offset + 1
+			mod.Properties = mod.Properties[1:]
+			continue
+		}
+
+		prop := mod.Properties[idx]
+		mod.Properties = append(mod.Properties[:idx], mod.Properties[idx+1:]...)
+
+		stage += string(buf[prop.Pos().Offset : prop.End().Offset+1])
+
+		err := patchlist.Add(prop.Pos().Offset, prop.End().Offset+2, "")
+		if err != nil {
+			return err
+		}
+	}
+
+	if stage != "" {
+		err := patchlist.Add(pos, pos, stage)
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func removeTags(mod *parser.Module, buf []byte, patchlist *parser.PatchList) error {
+	prop, ok := mod.GetProperty("tags")
+	if !ok {
+		return nil
+	}
+	list, ok := prop.Value.(*parser.List)
+	if !ok {
+		return nil
+	}
+
+	replaceStr := ""
+
+	for _, item := range list.Values {
+		str, ok := item.(*parser.String)
+		if !ok {
+			replaceStr += fmt.Sprintf("// ERROR: Unable to parse tag %q\n", item)
+			continue
+		}
+
+		switch str.Value {
+		case "optional":
+			continue
+		case "debug":
+			replaceStr += `// WARNING: Module tags are not supported in Soong.
+				// Add this module to PRODUCT_PACKAGES_DEBUG in your product file if you want to
+				// force installation for -userdebug and -eng builds.
+				`
+		case "eng":
+			replaceStr += `// WARNING: Module tags are not supported in Soong.
+				// Add this module to PRODUCT_PACKAGES_ENG in your product file if you want to
+				// force installation for -eng builds.
+				`
+		case "tests":
+			if strings.Contains(mod.Type, "cc_test") || strings.Contains(mod.Type, "cc_library_static") {
+				continue
+			} else if strings.Contains(mod.Type, "cc_lib") {
+				replaceStr += `// WARNING: Module tags are not supported in Soong.
+					// To make a shared library only for tests, use the "cc_test_library" module
+					// type. If you don't use gtest, set "gtest: false".
+					`
+			} else if strings.Contains(mod.Type, "cc_bin") {
+				replaceStr += `// WARNING: Module tags are not supported in Soong.
+					// For native test binaries, use the "cc_test" module type. Some differences:
+					//  - If you don't use gtest, set "gtest: false"
+					//  - Binaries will be installed into /data/nativetest[64]/<name>/<name>
+					//  - Both 32 & 64 bit versions will be built (as appropriate)
+					`
+			} else if strings.Contains(mod.Type, "java_lib") {
+				replaceStr += `// WARNING: Module tags are not supported in Soong.
+					// For JUnit or similar tests, use the "java_test" module type. A dependency on
+					// Junit will be added by default, if it is using some other runner, set "junit: false".
+					`
+			} else {
+				replaceStr += `// WARNING: Module tags are not supported in Soong.
+					// In most cases, tests are now identified by their module type:
+					// cc_test, java_test, python_test
+					`
+			}
+		default:
+			replaceStr += fmt.Sprintf("// WARNING: Unknown module tag %q\n", str.Value)
+		}
+	}
+
+	return patchlist.Add(prop.Pos().Offset, prop.End().Offset+2, replaceStr)
+}
+
+func mergeMatchingModuleProperties(mod *parser.Module, buf []byte, patchlist *parser.PatchList) error {
+	return mergeMatchingProperties(&mod.Properties, buf, patchlist)
+}
+
 func mergeMatchingProperties(properties *[]*parser.Property, buf []byte, patchlist *parser.PatchList) error {
 	seen := make(map[string]*parser.Property)
 	for i := 0; i < len(*properties); i++ {
@@ -354,7 +505,7 @@
 }
 
 // removes from <items> every item present in <removals>
-func filterExpressionList(items *parser.List, removals *parser.List) {
+func filterExpressionList(patchList *parser.PatchList, items *parser.List, removals *parser.List) {
 	writeIndex := 0
 	for _, item := range items.Values {
 		included := true
@@ -371,28 +522,39 @@
 		if included {
 			items.Values[writeIndex] = item
 			writeIndex++
+		} else {
+			patchList.Add(item.Pos().Offset, item.End().Offset+2, "")
 		}
 	}
 	items.Values = items.Values[:writeIndex]
 }
 
 // Remove each modules[i].Properties[<legacyName>][j] that matches a modules[i].Properties[<canonicalName>][k]
-func (f *Fixer) removeMatchingModuleListProperties(canonicalName string, legacyName string) error {
-	for _, def := range f.tree.Defs {
-		mod, ok := def.(*parser.Module)
-		if !ok {
-			continue
-		}
-		legacyList, ok := getLiteralListProperty(mod, legacyName)
-		if !ok {
-			continue
-		}
-		canonicalList, ok := getLiteralListProperty(mod, canonicalName)
-		if !ok {
-			continue
-		}
-		filterExpressionList(legacyList, canonicalList)
+func removeMatchingModuleListProperties(mod *parser.Module, patchList *parser.PatchList, canonicalName string, legacyName string) error {
+	legacyProp, ok := mod.GetProperty(legacyName)
+	if !ok {
+		return nil
 	}
+	legacyList, ok := legacyProp.Value.(*parser.List)
+	if !ok || len(legacyList.Values) == 0 {
+		return nil
+	}
+	canonicalList, ok := getLiteralListProperty(mod, canonicalName)
+	if !ok {
+		return nil
+	}
+
+	localPatches := parser.PatchList{}
+	filterExpressionList(&localPatches, legacyList, canonicalList)
+
+	if len(legacyList.Values) == 0 {
+		patchList.Add(legacyProp.Pos().Offset, legacyProp.End().Offset+2, "")
+	} else {
+		for _, p := range localPatches {
+			patchList.Add(p.Start, p.End, p.Replacement)
+		}
+	}
+
 	return nil
 }
 
@@ -410,6 +572,15 @@
 	return list, ok
 }
 
+func propertyIndex(props []*parser.Property, propertyName string) int {
+	for i, prop := range props {
+		if prop.Name == propertyName {
+			return i
+		}
+	}
+	return -1
+}
+
 func renameProperty(mod *parser.Module, from, to string) {
 	for _, prop := range mod.Properties {
 		if prop.Name == from {
diff --git a/bpfix/bpfix/bpfix_test.go b/bpfix/bpfix/bpfix_test.go
index 51708eb..654ccf9 100644
--- a/bpfix/bpfix/bpfix_test.go
+++ b/bpfix/bpfix/bpfix_test.go
@@ -66,27 +66,31 @@
 	fixer := NewFixer(tree)
 
 	// apply simplifications
-	err := fixer.simplifyKnownPropertiesDuplicatingEachOther()
+	err := fixer.runPatchListMod(simplifyKnownPropertiesDuplicatingEachOther)
 	if len(errs) > 0 {
 		t.Fatal(err)
 	}
 
 	// lookup legacy property
 	mod := fixer.tree.Defs[0].(*parser.Module)
-	_, found := mod.GetProperty("local_include_dirs")
-	if !found {
-		t.Fatalf("failed to include key local_include_dirs in parse tree")
+
+	expectedResultString := fmt.Sprintf("%q", expectedResult)
+	if expectedResult == nil {
+		expectedResultString = "unset"
 	}
 
 	// check that the value for the legacy property was updated to the correct value
 	errorHeader := fmt.Sprintf("\nFailed to correctly simplify key 'local_include_dirs' in the presence of 'export_include_dirs.'\n"+
 		"original local_include_dirs: %q\n"+
 		"original export_include_dirs: %q\n"+
-		"expected result: %q\n"+
+		"expected result: %s\n"+
 		"actual result: ",
-		local_include_dirs, export_include_dirs, expectedResult)
-	result, ok := mod.GetProperty("local_include_dirs")
-	if !ok {
+		local_include_dirs, export_include_dirs, expectedResultString)
+	result, found := mod.GetProperty("local_include_dirs")
+	if !found {
+		if expectedResult == nil {
+			return
+		}
 		t.Fatal(errorHeader + "property not found")
 	}
 
@@ -95,6 +99,10 @@
 		t.Fatalf("%sproperty is not a list: %v", errorHeader, listResult)
 	}
 
+	if expectedResult == nil {
+		t.Fatalf("%sproperty exists: %v", errorHeader, listResult)
+	}
+
 	actualExpressions := listResult.Values
 	actualValues := make([]string, 0)
 	for _, expr := range actualExpressions {
@@ -109,7 +117,7 @@
 
 func TestSimplifyKnownVariablesDuplicatingEachOther(t *testing.T) {
 	// TODO use []Expression{} once buildTree above can support it (which is after b/38325146 is done)
-	implFilterListTest(t, []string{"include"}, []string{"include"}, []string{})
+	implFilterListTest(t, []string{"include"}, []string{"include"}, nil)
 	implFilterListTest(t, []string{"include1"}, []string{"include2"}, []string{"include1"})
 	implFilterListTest(t, []string{"include1", "include2", "include3", "include4"}, []string{"include2"},
 		[]string{"include1", "include3", "include4"})
@@ -117,6 +125,49 @@
 	implFilterListTest(t, []string{}, []string{}, []string{})
 }
 
+func runPass(t *testing.T, in, out string, innerTest func(*Fixer) error) {
+	expected, err := Reformat(out)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	in, err = Reformat(in)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	tree, errs := parser.Parse("<testcase>", bytes.NewBufferString(in), parser.NewScope(nil))
+	if errs != nil {
+		t.Fatal(errs)
+	}
+
+	fixer := NewFixer(tree)
+
+	got := ""
+	prev := "foo"
+	passes := 0
+	for got != prev && passes < 10 {
+		err := innerTest(fixer)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		out, err := parser.Print(fixer.tree)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		prev = got
+		got = string(out)
+		passes++
+	}
+
+	if got != expected {
+		t.Errorf("output didn't match:\ninput:\n%s\n\nexpected:\n%s\ngot:\n%s\n",
+			in, expected, got)
+	}
+}
+
 func TestMergeMatchingProperties(t *testing.T) {
 	tests := []struct {
 		name string
@@ -199,47 +250,250 @@
 
 	for _, test := range tests {
 		t.Run(test.name, func(t *testing.T) {
-			expected, err := Reformat(test.out)
-			if err != nil {
-				t.Error(err)
-			}
+			runPass(t, test.in, test.out, func(fixer *Fixer) error {
+				return fixer.runPatchListMod(mergeMatchingModuleProperties)
+			})
+		})
+	}
+}
 
-			in, err := Reformat(test.in)
-			if err != nil {
-				t.Error(err)
-			}
-
-			tree, errs := parser.Parse("<testcase>", bytes.NewBufferString(in), parser.NewScope(nil))
-			if errs != nil {
-				t.Fatal(errs)
-			}
-
-			fixer := NewFixer(tree)
-
-			got := ""
-			prev := "foo"
-			passes := 0
-			for got != prev && passes < 10 {
-				err := fixer.mergeMatchingModuleProperties()
-				if err != nil {
-					t.Fatal(err)
+func TestReorderCommonProperties(t *testing.T) {
+	var tests = []struct {
+		name string
+		in   string
+		out  string
+	}{
+		{
+			name: "empty",
+			in:   `cc_library {}`,
+			out:  `cc_library {}`,
+		},
+		{
+			name: "only priority",
+			in: `
+				cc_library {
+					name: "foo",
 				}
-
-				out, err := parser.Print(fixer.tree)
-				if err != nil {
-					t.Fatal(err)
+			`,
+			out: `
+				cc_library {
+					name: "foo",
 				}
+			`,
+		},
+		{
+			name: "already in order",
+			in: `
+				cc_library {
+					name: "foo",
+					defaults: ["bar"],
+				}
+			`,
+			out: `
+				cc_library {
+					name: "foo",
+					defaults: ["bar"],
+				}
+			`,
+		},
+		{
+			name: "reorder only priority",
+			in: `
+				cc_library {
+					defaults: ["bar"],
+					name: "foo",
+				}
+			`,
+			out: `
+				cc_library {
+					name: "foo",
+					defaults: ["bar"],
+				}
+			`,
+		},
+		{
+			name: "reorder",
+			in: `
+				cc_library {
+					name: "foo",
+					srcs: ["a.c"],
+					host_supported: true,
+					defaults: ["bar"],
+					shared_libs: ["baz"],
+				}
+			`,
+			out: `
+				cc_library {
+					name: "foo",
+					defaults: ["bar"],
+					host_supported: true,
+					srcs: ["a.c"],
+					shared_libs: ["baz"],
+				}
+			`,
+		},
+	}
 
-				prev = got
-				got = string(out)
-				passes++
-			}
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			runPass(t, test.in, test.out, func(fixer *Fixer) error {
+				return fixer.runPatchListMod(reorderCommonProperties)
+			})
+		})
+	}
+}
 
-			if got != expected {
-				t.Errorf("failed testcase '%s'\ninput:\n%s\n\nexpected:\n%s\ngot:\n%s\n",
-					test.name, in, expected, got)
-			}
+func TestRemoveMatchingModuleListProperties(t *testing.T) {
+	var tests = []struct {
+		name string
+		in   string
+		out  string
+	}{
+		{
+			name: "simple",
+			in: `
+				cc_library {
+					name: "foo",
+					foo: ["a"],
+					bar: ["a"],
+				}
+			`,
+			out: `
+				cc_library {
+					name: "foo",
+					bar: ["a"],
+				}
+			`,
+		},
+		{
+			name: "long",
+			in: `
+				cc_library {
+					name: "foo",
+					foo: [
+						"a",
+						"b",
+					],
+					bar: ["a"],
+				}
+			`,
+			out: `
+				cc_library {
+					name: "foo",
+					foo: [
+						"b",
+					],
+					bar: ["a"],
+				}
+			`,
+		},
+		{
+			name: "long fully removed",
+			in: `
+				cc_library {
+					name: "foo",
+					foo: [
+						"a",
+					],
+					bar: ["a"],
+				}
+			`,
+			out: `
+				cc_library {
+					name: "foo",
+					bar: ["a"],
+				}
+			`,
+		},
+		{
+			name: "comment",
+			in: `
+				cc_library {
+					name: "foo",
 
+					// comment
+					foo: ["a"],
+
+					bar: ["a"],
+				}
+			`,
+			out: `
+				cc_library {
+					name: "foo",
+
+					// comment
+
+					bar: ["a"],
+				}
+			`,
+		},
+		{
+			name: "inner comment",
+			in: `
+				cc_library {
+					name: "foo",
+					foo: [
+						// comment
+						"a",
+					],
+					bar: ["a"],
+				}
+			`,
+			out: `
+				cc_library {
+					name: "foo",
+					bar: ["a"],
+				}
+			`,
+		},
+		{
+			name: "eol comment",
+			in: `
+				cc_library {
+					name: "foo",
+					foo: ["a"], // comment
+					bar: ["a"],
+				}
+			`,
+			out: `
+				cc_library {
+					name: "foo",
+					// comment
+					bar: ["a"],
+				}
+			`,
+		},
+		{
+			name: "eol comment with blank lines",
+			in: `
+				cc_library {
+					name: "foo",
+
+					foo: ["a"], // comment
+
+					// bar
+					bar: ["a"],
+				}
+			`,
+			out: `
+				cc_library {
+					name: "foo",
+
+					// comment
+
+					// bar
+					bar: ["a"],
+				}
+			`,
+		},
+	}
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			runPass(t, test.in, test.out, func(fixer *Fixer) error {
+				return fixer.runPatchListMod(func(mod *parser.Module, buf []byte, patchList *parser.PatchList) error {
+					return removeMatchingModuleListProperties(mod, patchList, "bar", "foo")
+				})
+			})
 		})
 	}
 }
diff --git a/bpfix/cmd/bpfix.go b/bpfix/cmd/bpfix.go
index 2fde383..ccdae16 100644
--- a/bpfix/cmd/bpfix.go
+++ b/bpfix/cmd/bpfix.go
@@ -65,7 +65,7 @@
 	if err != nil {
 		return err
 	}
-	r := bytes.NewBuffer(src)
+	r := bytes.NewBuffer(append([]byte(nil), src...))
 	file, errs := parser.Parse(filename, r, parser.NewScope(nil))
 	if len(errs) > 0 {
 		for _, err := range errs {
diff --git a/cc/androidmk.go b/cc/androidmk.go
index cdd4a5a..f417de0 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -24,7 +24,8 @@
 )
 
 var (
-	vendorSuffix = ".vendor"
+	vendorSuffix   = ".vendor"
+	recoverySuffix = ".recovery"
 )
 
 type AndroidMkContext interface {
@@ -99,6 +100,8 @@
 		// .vendor suffix is added only when we will have two variants: core and vendor.
 		// The suffix is not added for vendor-only module.
 		ret.SubName += vendorSuffix
+	} else if c.inRecovery() && !c.onlyInRecovery() {
+		ret.SubName += recoverySuffix
 	}
 
 	return ret
@@ -345,7 +348,7 @@
 
 func (c *llndkStubDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
 	ret.Class = "SHARED_LIBRARIES"
-	ret.SubName = ".vendor"
+	ret.SubName = vendorSuffix
 
 	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
 		c.libraryDecorator.androidMkWriteExportedFlags(w)
diff --git a/cc/binary.go b/cc/binary.go
index 9e7b70b..00fda06 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -353,6 +353,11 @@
 }
 
 func (binary *binaryDecorator) install(ctx ModuleContext, file android.Path) {
+	// <recovery>/bin is a symlink to /system/bin. Recovery binaries are all in /sbin.
+	if ctx.inRecovery() {
+		binary.baseInstaller.dir = "sbin"
+	}
+
 	binary.baseInstaller.install(ctx, file)
 	for _, symlink := range binary.Properties.Symlinks {
 		binary.symlinks = append(binary.symlinks,
diff --git a/cc/cc.go b/cc/cc.go
index 76e6645..a885c91 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -34,7 +34,7 @@
 	android.RegisterModuleType("cc_defaults", defaultsFactory)
 
 	android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.BottomUp("image", vendorMutator).Parallel()
+		ctx.BottomUp("image", imageMutator).Parallel()
 		ctx.BottomUp("link", linkageMutator).Parallel()
 		ctx.BottomUp("vndk", vndkMutator).Parallel()
 		ctx.BottomUp("ndk_api", ndkApiMutator).Parallel()
@@ -175,6 +175,11 @@
 	// *.logtags files, to combine together in order to generate the /system/etc/event-log-tags
 	// file
 	Logtags []string
+
+	// Make this module available when building for recovery
+	Recovery_available *bool
+
+	InRecovery bool `blueprint:"mutated"`
 }
 
 type VendorProperties struct {
@@ -206,10 +211,6 @@
 	Double_loadable *bool
 }
 
-type UnusedProperties struct {
-	Tags []string
-}
-
 type ModuleContextIntf interface {
 	static() bool
 	staticBinary() bool
@@ -221,6 +222,7 @@
 	isVndk() bool
 	isVndkSp() bool
 	isVndkExt() bool
+	inRecovery() bool
 	createVndkSourceAbiDump() bool
 	selectedStl() string
 	baseModuleName() string
@@ -320,7 +322,6 @@
 
 	Properties       BaseProperties
 	VendorProperties VendorProperties
-	unused           UnusedProperties
 
 	// initialize before calling Init
 	hod      android.HostOrDeviceSupported
@@ -360,7 +361,7 @@
 }
 
 func (c *Module) Init() android.Module {
-	c.AddProperties(&c.Properties, &c.VendorProperties, &c.unused)
+	c.AddProperties(&c.Properties, &c.VendorProperties)
 	if c.compiler != nil {
 		c.AddProperties(c.compiler.compilerProps()...)
 	}
@@ -458,6 +459,14 @@
 	return c.isVndk() || Bool(c.VendorProperties.Vendor_available)
 }
 
+func (c *Module) inRecovery() bool {
+	return c.Properties.InRecovery || c.ModuleBase.InstallInRecovery()
+}
+
+func (c *Module) onlyInRecovery() bool {
+	return c.ModuleBase.InstallInRecovery()
+}
+
 type baseModuleContext struct {
 	android.BaseContext
 	moduleContextImpl
@@ -505,7 +514,7 @@
 }
 
 func (ctx *moduleContextImpl) useSdk() bool {
-	if ctx.ctx.Device() && !ctx.useVndk() {
+	if ctx.ctx.Device() && !ctx.useVndk() && !ctx.inRecovery() {
 		return String(ctx.mod.Properties.Sdk_version) != ""
 	}
 	return false
@@ -549,16 +558,20 @@
 	return ctx.mod.isVndkExt()
 }
 
+func (ctx *moduleContextImpl) inRecovery() bool {
+	return ctx.mod.inRecovery()
+}
+
 // Create source abi dumps if the module belongs to the list of VndkLibraries.
 func (ctx *moduleContextImpl) createVndkSourceAbiDump() bool {
 	skipAbiChecks := ctx.ctx.Config().IsEnvTrue("SKIP_ABI_CHECKS")
-	isUnsanitizedVariant := true
+	isVariantOnProductionDevice := true
 	sanitize := ctx.mod.sanitize
 	if sanitize != nil {
-		isUnsanitizedVariant = sanitize.isUnsanitizedVariant()
+		isVariantOnProductionDevice = sanitize.isVariantOnProductionDevice()
 	}
 	vendorAvailable := Bool(ctx.mod.VendorProperties.Vendor_available)
-	return !skipAbiChecks && isUnsanitizedVariant && ctx.ctx.Device() && ((ctx.useVndk() && ctx.isVndk() && vendorAvailable) || inList(ctx.baseModuleName(), llndkLibraries))
+	return !skipAbiChecks && isVariantOnProductionDevice && ctx.ctx.Device() && ((ctx.useVndk() && ctx.isVndk() && vendorAvailable) || inList(ctx.baseModuleName(), llndkLibraries))
 }
 
 func (ctx *moduleContextImpl) selectedStl() string {
@@ -1074,6 +1087,10 @@
 		// Platform code can link to anything
 		return
 	}
+	if from.inRecovery() {
+		// Recovery code is not NDK
+		return
+	}
 	if _, ok := to.linker.(*toolchainLibraryDecorator); ok {
 		// These are always allowed
 		return
@@ -1365,6 +1382,8 @@
 				return libName + vendorSuffix
 			} else if (ctx.Platform() || ctx.ProductSpecific()) && isVendorPublicLib {
 				return libName + vendorPublicLibrarySuffix
+			} else if ccDep.inRecovery() && !ccDep.onlyInRecovery() {
+				return libName + recoverySuffix
 			} else {
 				return libName
 			}
@@ -1416,6 +1435,10 @@
 	return c.installer.inSanitizerDir()
 }
 
+func (c *Module) InstallInRecovery() bool {
+	return c.inRecovery()
+}
+
 func (c *Module) HostToolPath() android.OptionalPath {
 	if c.installer == nil {
 		return android.OptionalPath{}
@@ -1475,7 +1498,6 @@
 		&BinaryLinkerProperties{},
 		&TestProperties{},
 		&TestBinaryProperties{},
-		&UnusedProperties{},
 		&StlProperties{},
 		&SanitizeProperties{},
 		&StripProperties{},
@@ -1502,6 +1524,8 @@
 	// vendorMode is the variant used for /vendor code that compiles
 	// against the VNDK.
 	vendorMode = "vendor"
+
+	recoveryMode = "recovery"
 )
 
 func squashVendorSrcs(m *Module) {
@@ -1514,7 +1538,17 @@
 	}
 }
 
-func vendorMutator(mctx android.BottomUpMutatorContext) {
+func squashRecoverySrcs(m *Module) {
+	if lib, ok := m.compiler.(*libraryDecorator); ok {
+		lib.baseCompiler.Properties.Srcs = append(lib.baseCompiler.Properties.Srcs,
+			lib.baseCompiler.Properties.Target.Recovery.Srcs...)
+
+		lib.baseCompiler.Properties.Exclude_srcs = append(lib.baseCompiler.Properties.Exclude_srcs,
+			lib.baseCompiler.Properties.Target.Recovery.Exclude_srcs...)
+	}
+}
+
+func imageMutator(mctx android.BottomUpMutatorContext) {
 	if mctx.Os() != android.Android {
 		return
 	}
@@ -1583,43 +1617,70 @@
 		}
 	}
 
+	var coreVariantNeeded bool = false
+	var vendorVariantNeeded bool = false
+	var recoveryVariantNeeded bool = false
+
 	if mctx.DeviceConfig().VndkVersion() == "" {
 		// If the device isn't compiling against the VNDK, we always
 		// use the core mode.
-		mctx.CreateVariations(coreMode)
+		coreVariantNeeded = true
 	} else if _, ok := m.linker.(*llndkStubDecorator); ok {
 		// LL-NDK stubs only exist in the vendor variant, since the
 		// real libraries will be used in the core variant.
-		mctx.CreateVariations(vendorMode)
+		vendorVariantNeeded = true
 	} else if _, ok := m.linker.(*llndkHeadersDecorator); ok {
 		// ... and LL-NDK headers as well
-		mod := mctx.CreateVariations(vendorMode)
-		vendor := mod[0].(*Module)
-		vendor.Properties.UseVndk = true
+		vendorVariantNeeded = true
 	} else if _, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok {
 		// Make vendor variants only for the versions in BOARD_VNDK_VERSION and
 		// PRODUCT_EXTRA_VNDK_VERSIONS.
-		mod := mctx.CreateVariations(vendorMode)
-		vendor := mod[0].(*Module)
-		vendor.Properties.UseVndk = true
+		vendorVariantNeeded = true
 	} else if m.hasVendorVariant() && !vendorSpecific {
 		// This will be available in both /system and /vendor
 		// or a /system directory that is available to vendor.
-		mod := mctx.CreateVariations(coreMode, vendorMode)
-		vendor := mod[1].(*Module)
-		vendor.Properties.UseVndk = true
-		squashVendorSrcs(vendor)
+		coreVariantNeeded = true
+		vendorVariantNeeded = true
 	} else if vendorSpecific && 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
-		squashVendorSrcs(vendor)
+		vendorVariantNeeded = true
 	} else {
 		// This is either in /system (or similar: /data), or is a
 		// modules built with the NDK. Modules built with the NDK
 		// will be restricted using the existing link type checks.
-		mctx.CreateVariations(coreMode)
+		coreVariantNeeded = true
+	}
+
+	if Bool(m.Properties.Recovery_available) {
+		recoveryVariantNeeded = true
+	}
+
+	if m.ModuleBase.InstallInRecovery() {
+		recoveryVariantNeeded = true
+		coreVariantNeeded = false
+	}
+
+	var variants []string
+	if coreVariantNeeded {
+		variants = append(variants, coreMode)
+	}
+	if vendorVariantNeeded {
+		variants = append(variants, vendorMode)
+	}
+	if recoveryVariantNeeded {
+		variants = append(variants, recoveryMode)
+	}
+	mod := mctx.CreateVariations(variants...)
+	for i, v := range variants {
+		if v == vendorMode {
+			m := mod[i].(*Module)
+			m.Properties.UseVndk = true
+			squashVendorSrcs(m)
+		} else if v == recoveryMode {
+			m := mod[i].(*Module)
+			m.Properties.InRecovery = true
+			squashRecoverySrcs(m)
+		}
 	}
 }
 
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 4f26827..1b12ad4 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -63,7 +63,7 @@
 	ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(objectFactory))
 	ctx.RegisterModuleType("filegroup", android.ModuleFactoryAdaptor(android.FileGroupFactory))
 	ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.BottomUp("image", vendorMutator).Parallel()
+		ctx.BottomUp("image", imageMutator).Parallel()
 		ctx.BottomUp("link", linkageMutator).Parallel()
 		ctx.BottomUp("vndk", vndkMutator).Parallel()
 		ctx.BottomUp("begin", beginMutator).Parallel()
diff --git a/cc/compiler.go b/cc/compiler.go
index 2ba19f1..b410115 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -142,6 +142,19 @@
 			// variant of the C/C++ module.
 			Cflags []string
 		}
+		Recovery struct {
+			// list of source files that should only be used in the
+			// recovery variant of the C/C++ module.
+			Srcs []string
+
+			// list of source files that should not be used to
+			// build the recovery variant of the C/C++ module.
+			Exclude_srcs []string
+
+			// List of additional cflags that should be used to build the recovery
+			// variant of the C/C++ module.
+			Cflags []string
+		}
 	}
 
 	Proto struct {
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index 74c936f..73d9e3b 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -27,6 +27,15 @@
 		"-Werror=implicit-function-declaration",
 	}
 
+	arm64ArchVariantCflags = map[string][]string{
+		"armv8-a": []string{
+			"-march=armv8-a",
+		},
+		"armv8-2a": []string{
+			"-march=armv8.2a",
+		},
+	}
+
 	arm64Ldflags = []string{
 		"-Wl,-m,aarch64_elf64_le_vec",
 		"-Wl,--hash-style=gnu",
@@ -44,6 +53,17 @@
 		"cortex-a53": []string{
 			"-mcpu=cortex-a53",
 		},
+		"cortex-a55": []string{
+			// The cortex-a55 target is not yet supported,
+			// so use cortex-a53.
+			"-mcpu=cortex-a53",
+		},
+		"cortex-a75": []string{
+			// Use the cortex-a53 since it is similar to the little
+			// core (cortex-a55) and is sensitive to ordering.
+			// The cortex-a55 target is not yet supported.
+			"-mcpu=cortex-a53",
+		},
 		"kryo": []string{
 			// Use the cortex-a57 cpu since some compilers
 			// don't support a Kryo specific target yet.
@@ -67,8 +87,11 @@
 func init() {
 	android.RegisterArchVariants(android.Arm64,
 		"armv8_a",
+		"armv8_2a",
 		"cortex-a53",
+		"cortex-a55",
 		"cortex-a73",
+		"cortex-a75",
 		"kryo",
 		"exynos-m1",
 		"exynos-m2",
@@ -93,11 +116,19 @@
 	pctx.StaticVariable("Arm64ClangLldflags", strings.Join(ClangFilterUnknownCflags(arm64Lldflags), " "))
 	pctx.StaticVariable("Arm64ClangCppflags", strings.Join(ClangFilterUnknownCflags(arm64Cppflags), " "))
 
+	pctx.StaticVariable("Arm64ClangArmv8ACflags", strings.Join(arm64ArchVariantCflags["armv8-a"], " "))
+	pctx.StaticVariable("Arm64ClangArmv82ACflags", strings.Join(arm64ArchVariantCflags["armv8-2a"], " "))
+
 	pctx.StaticVariable("Arm64CortexA53Cflags",
 		strings.Join(arm64CpuVariantCflags["cortex-a53"], " "))
 	pctx.StaticVariable("Arm64ClangCortexA53Cflags",
 		strings.Join(arm64ClangCpuVariantCflags["cortex-a53"], " "))
 
+	pctx.StaticVariable("Arm64CortexA55Cflags",
+		strings.Join(arm64CpuVariantCflags["cortex-a55"], " "))
+	pctx.StaticVariable("Arm64ClangCortexA55Cflags",
+		strings.Join(arm64ClangCpuVariantCflags["cortex-a55"], " "))
+
 	pctx.StaticVariable("Arm64KryoCflags",
 		strings.Join(arm64CpuVariantCflags["kryo"], " "))
 	pctx.StaticVariable("Arm64ClangKryoCflags",
@@ -118,16 +149,25 @@
 	arm64CpuVariantCflagsVar = map[string]string{
 		"":           "",
 		"cortex-a53": "${config.Arm64CortexA53Cflags}",
+		"cortex-a55": "${config.Arm64CortexA55Cflags}",
 		"cortex-a73": "${config.Arm64CortexA53Cflags}",
+		"cortex-a75": "${config.Arm64CortexA55Cflags}",
 		"kryo":       "${config.Arm64KryoCflags}",
 		"exynos-m1":  "${config.Arm64ExynosM1Cflags}",
 		"exynos-m2":  "${config.Arm64ExynosM2Cflags}",
 	}
 
+	arm64ClangArchVariantCflagsVar = map[string]string{
+		"armv8-a":  "${config.Arm64ClangArmv8ACflags}",
+		"armv8-2a": "${config.Arm64ClangArmv82ACflags}",
+	}
+
 	arm64ClangCpuVariantCflagsVar = map[string]string{
 		"":           "",
 		"cortex-a53": "${config.Arm64ClangCortexA53Cflags}",
+		"cortex-a55": "${config.Arm64ClangCortexA55Cflags}",
 		"cortex-a73": "${config.Arm64ClangCortexA53Cflags}",
+		"cortex-a75": "${config.Arm64ClangCortexA55Cflags}",
 		"kryo":       "${config.Arm64ClangKryoCflags}",
 		"exynos-m1":  "${config.Arm64ClangExynosM1Cflags}",
 		"exynos-m2":  "${config.Arm64ClangExynosM2Cflags}",
@@ -206,13 +246,21 @@
 }
 
 func arm64ToolchainFactory(arch android.Arch) Toolchain {
-	if arch.ArchVariant != "armv8-a" {
+	switch arch.ArchVariant {
+	case "armv8-a":
+	case "armv8-2a":
+		// Nothing extra for armv8-a/armv8-2a
+	default:
 		panic(fmt.Sprintf("Unknown ARM architecture version: %q", arch.ArchVariant))
 	}
 
+	toolchainClangCflags := []string{arm64ClangArchVariantCflagsVar[arch.ArchVariant]}
+	toolchainClangCflags = append(toolchainClangCflags,
+		variantOrDefault(arm64ClangCpuVariantCflagsVar, arch.CpuVariant))
+
 	return &toolchainArm64{
 		toolchainCflags:      variantOrDefault(arm64CpuVariantCflagsVar, arch.CpuVariant),
-		toolchainClangCflags: variantOrDefault(arm64ClangCpuVariantCflagsVar, arch.CpuVariant),
+		toolchainClangCflags: strings.Join(toolchainClangCflags, " "),
 	}
 }
 
diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go
index 02bd9eb..398df90 100644
--- a/cc/config/arm_device.go
+++ b/cc/config/arm_device.go
@@ -99,6 +99,24 @@
 			// better solution comes around. See Bug 27340895
 			"-D__ARM_FEATURE_LPAE=1",
 		},
+		"cortex-a55": []string{
+			"-mcpu=cortex-a53",
+			"-mfpu=neon-fp-armv8",
+			// Fake an ARM compiler flag as these processors support LPAE which GCC/clang
+			// don't advertise.
+			// TODO This is a hack and we need to add it for each processor that supports LPAE until some
+			// better solution comes around. See Bug 27340895
+			"-D__ARM_FEATURE_LPAE=1",
+		},
+		"cortex-a75": []string{
+			"-mcpu=cortex-a53",
+			"-mfpu=neon-fp-armv8",
+			// Fake an ARM compiler flag as these processors support LPAE which GCC/clang
+			// don't advertise.
+			// TODO This is a hack and we need to add it for each processor that supports LPAE until some
+			// better solution comes around. See Bug 27340895
+			"-D__ARM_FEATURE_LPAE=1",
+		},
 		"krait": []string{
 			"-mcpu=cortex-a15",
 			"-mfpu=neon-vfpv4",
@@ -143,7 +161,9 @@
 		"cortex-a15",
 		"cortex-a53",
 		"cortex-a53-a57",
+		"cortex-a55",
 		"cortex-a73",
+		"cortex-a75",
 		"krait",
 		"kryo",
 		"exynos-m1",
@@ -192,6 +212,7 @@
 	pctx.StaticVariable("ArmCortexA8Cflags", strings.Join(armCpuVariantCflags["cortex-a8"], " "))
 	pctx.StaticVariable("ArmCortexA15Cflags", strings.Join(armCpuVariantCflags["cortex-a15"], " "))
 	pctx.StaticVariable("ArmCortexA53Cflags", strings.Join(armCpuVariantCflags["cortex-a53"], " "))
+	pctx.StaticVariable("ArmCortexA55Cflags", strings.Join(armCpuVariantCflags["cortex-a55"], " "))
 	pctx.StaticVariable("ArmKraitCflags", strings.Join(armCpuVariantCflags["krait"], " "))
 	pctx.StaticVariable("ArmKryoCflags", strings.Join(armCpuVariantCflags["kryo"], " "))
 
@@ -225,6 +246,8 @@
 		strings.Join(armClangCpuVariantCflags["cortex-a15"], " "))
 	pctx.StaticVariable("ArmClangCortexA53Cflags",
 		strings.Join(armClangCpuVariantCflags["cortex-a53"], " "))
+	pctx.StaticVariable("ArmClangCortexA55Cflags",
+		strings.Join(armClangCpuVariantCflags["cortex-a55"], " "))
 	pctx.StaticVariable("ArmClangKraitCflags",
 		strings.Join(armClangCpuVariantCflags["krait"], " "))
 	pctx.StaticVariable("ArmClangKryoCflags",
@@ -245,7 +268,9 @@
 		"cortex-a15":     "${config.ArmCortexA15Cflags}",
 		"cortex-a53":     "${config.ArmCortexA53Cflags}",
 		"cortex-a53.a57": "${config.ArmCortexA53Cflags}",
+		"cortex-a55":     "${config.ArmCortexA55Cflags}",
 		"cortex-a73":     "${config.ArmCortexA53Cflags}",
+		"cortex-a75":     "${config.ArmCortexA55Cflags}",
 		"krait":          "${config.ArmKraitCflags}",
 		"kryo":           "${config.ArmKryoCflags}",
 		"exynos-m1":      "${config.ArmCortexA53Cflags}",
@@ -266,7 +291,9 @@
 		"cortex-a15":     "${config.ArmClangCortexA15Cflags}",
 		"cortex-a53":     "${config.ArmClangCortexA53Cflags}",
 		"cortex-a53.a57": "${config.ArmClangCortexA53Cflags}",
+		"cortex-a55":     "${config.ArmClangCortexA55Cflags}",
 		"cortex-a73":     "${config.ArmClangCortexA53Cflags}",
+		"cortex-a75":     "${config.ArmClangCortexA55Cflags}",
 		"krait":          "${config.ArmClangKraitCflags}",
 		"kryo":           "${config.ArmClangKryoCflags}",
 		"exynos-m1":      "${config.ArmClangCortexA53Cflags}",
diff --git a/cc/library.go b/cc/library.go
index b31fee2..c83e89a 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -477,6 +477,11 @@
 		deps.SharedLibs = removeListFromList(deps.SharedLibs, library.baseLinker.Properties.Target.Vendor.Exclude_shared_libs)
 		deps.StaticLibs = removeListFromList(deps.StaticLibs, library.baseLinker.Properties.Target.Vendor.Exclude_static_libs)
 	}
+	if ctx.inRecovery() {
+		deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, library.baseLinker.Properties.Target.Recovery.Exclude_static_libs)
+		deps.SharedLibs = removeListFromList(deps.SharedLibs, library.baseLinker.Properties.Target.Recovery.Exclude_shared_libs)
+		deps.StaticLibs = removeListFromList(deps.StaticLibs, library.baseLinker.Properties.Target.Recovery.Exclude_static_libs)
+	}
 
 	android.ExtractSourceDeps(ctx, library.Properties.Version_script)
 	android.ExtractSourceDeps(ctx, library.Properties.Unexported_symbols_list)
@@ -745,7 +750,7 @@
 	}
 
 	if Bool(library.Properties.Static_ndk_lib) && library.static() &&
-		!ctx.useVndk() && ctx.Device() &&
+		!ctx.useVndk() && !ctx.inRecovery() && ctx.Device() &&
 		library.sanitize.isUnsanitizedVariant() {
 		installPath := getNdkSysrootBase(ctx).Join(
 			ctx, "usr/lib", config.NDKTriple(ctx.toolchain()), file.Base())
diff --git a/cc/linker.go b/cc/linker.go
index 71da09e..3e2ecc6 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -107,6 +107,15 @@
 			// variant of the C/C++ module.
 			Exclude_runtime_libs []string
 		}
+		Recovery struct {
+			// list of shared libs that should not be used to build
+			// the recovery variant of the C/C++ module.
+			Exclude_shared_libs []string
+
+			// list of static libs that should not be used to build
+			// the recovery variant of the C/C++ module.
+			Exclude_static_libs []string
+		}
 	}
 
 	// make android::build:GetBuildNumber() available containing the build ID.
@@ -166,6 +175,14 @@
 		deps.RuntimeLibs = removeListFromList(deps.RuntimeLibs, linker.Properties.Target.Vendor.Exclude_runtime_libs)
 	}
 
+	if ctx.inRecovery() {
+		deps.SharedLibs = removeListFromList(deps.SharedLibs, linker.Properties.Target.Recovery.Exclude_shared_libs)
+		deps.ReexportSharedLibHeaders = removeListFromList(deps.ReexportSharedLibHeaders, linker.Properties.Target.Recovery.Exclude_shared_libs)
+		deps.StaticLibs = removeListFromList(deps.StaticLibs, linker.Properties.Target.Recovery.Exclude_static_libs)
+		deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Recovery.Exclude_static_libs)
+		deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Recovery.Exclude_static_libs)
+	}
+
 	if ctx.ModuleName() != "libcompiler_rt-extras" {
 		deps.LateStaticLibs = append(deps.LateStaticLibs, "libcompiler_rt-extras")
 	}
diff --git a/cc/pgo.go b/cc/pgo.go
index d39e429..a341ab9 100644
--- a/cc/pgo.go
+++ b/cc/pgo.go
@@ -19,6 +19,8 @@
 	"path/filepath"
 	"strings"
 
+	"github.com/google/blueprint/proptools"
+
 	"android/soong/android"
 	"android/soong/cc/config"
 )
@@ -160,13 +162,8 @@
 		return flags
 	}
 
-	// Skip -fprofile-use if 'enable_profile_use' property is set
-	if props.Pgo.Enable_profile_use != nil && *props.Pgo.Enable_profile_use == false {
-		return flags
-	}
-
-	// If the profile file is found, add flags to use the profile
-	if profileFile := props.getPgoProfileFile(ctx); profileFile.Valid() {
+	if props.PgoCompile {
+		profileFile := props.getPgoProfileFile(ctx)
 		profileFilePath := profileFile.Path()
 		profileUseFlags := props.profileUseFlags(ctx, profileFilePath.String())
 
@@ -257,7 +254,8 @@
 		}
 	}
 
-	if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") {
+	if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") &&
+		proptools.BoolDefault(pgo.Properties.Pgo.Enable_profile_use, true) {
 		if profileFile := pgo.Properties.getPgoProfileFile(ctx); profileFile.Valid() {
 			pgo.Properties.PgoCompile = true
 		}
diff --git a/cc/proto.go b/cc/proto.go
index 22e50ab..6e6f95e 100644
--- a/cc/proto.go
+++ b/cc/proto.go
@@ -25,13 +25,17 @@
 
 func init() {
 	pctx.HostBinToolVariable("protocCmd", "aprotoc")
+	pctx.HostBinToolVariable("depFixCmd", "dep_fixer")
 }
 
 var (
 	proto = pctx.AndroidStaticRule("protoc",
 		blueprint.RuleParams{
-			Command:     "$protocCmd --cpp_out=$protoOutParams:$outDir -I $protoBase $protoFlags $in",
-			CommandDeps: []string{"$protocCmd"},
+			Command: "$protocCmd --cpp_out=$protoOutParams:$outDir --dependency_out=$out.d -I $protoBase $protoFlags $in && " +
+				`$depFixCmd $out.d`,
+			CommandDeps: []string{"$protocCmd", "$depFixCmd"},
+			Depfile:     "${out}.d",
+			Deps:        blueprint.DepsGCC,
 		}, "protoFlags", "protoOutParams", "protoBase", "outDir")
 )
 
@@ -53,10 +57,11 @@
 	}
 
 	ctx.Build(pctx, android.BuildParams{
-		Rule:        proto,
-		Description: "protoc " + protoFile.Rel(),
-		Outputs:     android.WritablePaths{ccFile, headerFile},
-		Input:       protoFile,
+		Rule:           proto,
+		Description:    "protoc " + protoFile.Rel(),
+		Output:         ccFile,
+		ImplicitOutput: headerFile,
+		Input:          protoFile,
 		Args: map[string]string{
 			"outDir":         android.ProtoDir(ctx).String(),
 			"protoFlags":     protoFlags,
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 859d876..a704cf1 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -307,10 +307,12 @@
 }
 
 func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags) Flags {
-	minimalRuntimePath := "${config.ClangAsanLibDir}/" + config.UndefinedBehaviorSanitizerMinimalRuntimeLibrary(ctx.toolchain()) + ".a"
+	minimalRuntimeLib := config.UndefinedBehaviorSanitizerMinimalRuntimeLibrary(ctx.toolchain()) + ".a"
+	minimalRuntimePath := "${config.ClangAsanLibDir}/" + minimalRuntimeLib
 
 	if ctx.Device() && sanitize.Properties.MinimalRuntimeDep {
 		flags.LdFlags = append(flags.LdFlags, minimalRuntimePath)
+		flags.LdFlags = append(flags.LdFlags, "-Wl,--exclude-libs,"+minimalRuntimeLib)
 	}
 	if !sanitize.Properties.SanitizerEnabled && !sanitize.Properties.UbsanRuntimeDep {
 		return flags
@@ -448,6 +450,7 @@
 			if enableMinimalRuntime(sanitize) {
 				flags.CFlags = append(flags.CFlags, strings.Join(minimalRuntimeFlags, " "))
 				flags.libFlags = append([]string{minimalRuntimePath}, flags.libFlags...)
+				flags.LdFlags = append(flags.LdFlags, "-Wl,--exclude-libs,"+minimalRuntimeLib)
 			}
 		}
 	}
@@ -539,6 +542,11 @@
 		!sanitize.isSanitizerEnabled(cfi)
 }
 
+func (sanitize *sanitize) isVariantOnProductionDevice() bool {
+	return !sanitize.isSanitizerEnabled(asan) &&
+		!sanitize.isSanitizerEnabled(tsan)
+}
+
 func (sanitize *sanitize) SetSanitizer(t sanitizerType, b bool) {
 	switch t {
 	case asan:
diff --git a/cc/test.go b/cc/test.go
index fef6367..5d0ef20 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -168,13 +168,17 @@
 }
 
 func (test *testDecorator) linkerInit(ctx BaseModuleContext, linker *baseLinker) {
-	// add ../../lib[64] to rpath so that out/host/linux-x86/nativetest/<test dir>/<test> can
+	// 1. Add ../../lib[64] to rpath so that out/host/linux-x86/nativetest/<test dir>/<test> can
 	// find out/host/linux-x86/lib[64]/library.so
-	runpath := "../../lib"
-	if ctx.toolchain().Is64Bit() {
-		runpath += "64"
+	// 2. Add ../../../lib[64] to rpath so that out/host/linux-x86/testcases/<test dir>/<CPU>/<test> can
+	// also find out/host/linux-x86/lib[64]/library.so
+	runpaths := []string{"../../lib", "../../../lib"}
+	for _, runpath := range runpaths {
+		if ctx.toolchain().Is64Bit() {
+			runpath += "64"
+		}
+		linker.dynamicProperties.RunPaths = append(linker.dynamicProperties.RunPaths, runpath)
 	}
-	linker.dynamicProperties.RunPaths = append(linker.dynamicProperties.RunPaths, runpath)
 
 	// add "" to rpath so that test binaries can find libraries in their own test directory
 	linker.dynamicProperties.RunPaths = append(linker.dynamicProperties.RunPaths, "")
diff --git a/cmd/dep_fixer/Android.bp b/cmd/dep_fixer/Android.bp
new file mode 100644
index 0000000..d2d1113
--- /dev/null
+++ b/cmd/dep_fixer/Android.bp
@@ -0,0 +1,23 @@
+// Copyright 2018 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+blueprint_go_binary {
+    name: "dep_fixer",
+    deps: ["androidmk-parser"],
+    srcs: [
+        "main.go",
+        "deps.go",
+    ],
+    testSrcs: ["deps_test.go"],
+}
diff --git a/cmd/dep_fixer/deps.go b/cmd/dep_fixer/deps.go
new file mode 100644
index 0000000..64c97f5
--- /dev/null
+++ b/cmd/dep_fixer/deps.go
@@ -0,0 +1,95 @@
+// Copyright 2018 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"strings"
+
+	"android/soong/androidmk/parser"
+)
+
+type Deps struct {
+	Output string
+	Inputs []string
+}
+
+func Parse(filename string, r io.Reader) (*Deps, error) {
+	p := parser.NewParser(filename, r)
+	nodes, errs := p.Parse()
+
+	if len(errs) == 1 {
+		return nil, errs[0]
+	} else if len(errs) > 1 {
+		return nil, fmt.Errorf("many errors: %v", errs)
+	}
+
+	pos := func(node parser.Node) string {
+		return p.Unpack(node.Pos()).String() + ": "
+	}
+
+	ret := &Deps{}
+
+	for _, node := range nodes {
+		switch x := node.(type) {
+		case *parser.Comment:
+			// Do nothing
+		case *parser.Rule:
+			if x.Recipe != "" {
+				return nil, fmt.Errorf("%sunexpected recipe in rule: %v", pos(node), x)
+			}
+
+			if !x.Target.Const() {
+				return nil, fmt.Errorf("%sunsupported variable expansion: %v", pos(node), x.Target.Dump())
+			}
+			outputs := x.Target.Words()
+			if len(outputs) == 0 {
+				return nil, fmt.Errorf("%smissing output: %v", pos(node), x)
+			}
+			ret.Output = outputs[0].Value(nil)
+
+			if !x.Prerequisites.Const() {
+				return nil, fmt.Errorf("%sunsupported variable expansion: %v", pos(node), x.Prerequisites.Dump())
+			}
+			for _, input := range x.Prerequisites.Words() {
+				ret.Inputs = append(ret.Inputs, input.Value(nil))
+			}
+		default:
+			return nil, fmt.Errorf("%sunexpected line: %#v", pos(node), node)
+		}
+	}
+
+	return ret, nil
+}
+
+func (d *Deps) Print() []byte {
+	// We don't really have to escape every \, but it's simpler,
+	// and ninja will handle it.
+	replacer := strings.NewReplacer(" ", "\\ ",
+		":", "\\:",
+		"#", "\\#",
+		"$", "$$",
+		"\\", "\\\\")
+
+	b := &bytes.Buffer{}
+	fmt.Fprintf(b, "%s:", replacer.Replace(d.Output))
+	for _, input := range d.Inputs {
+		fmt.Fprintf(b, " %s", replacer.Replace(input))
+	}
+	fmt.Fprintln(b)
+	return b.Bytes()
+}
diff --git a/cmd/dep_fixer/deps_test.go b/cmd/dep_fixer/deps_test.go
new file mode 100644
index 0000000..0a779b7
--- /dev/null
+++ b/cmd/dep_fixer/deps_test.go
@@ -0,0 +1,389 @@
+// Copyright 2018 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+	"bytes"
+	"io"
+	"io/ioutil"
+	"os"
+	"testing"
+)
+
+func TestParse(t *testing.T) {
+	testCases := []struct {
+		name   string
+		input  string
+		output Deps
+		err    error
+	}{
+		// These come from the ninja test suite
+		{
+			name:  "Basic",
+			input: "build/ninja.o: ninja.cc ninja.h eval_env.h manifest_parser.h",
+			output: Deps{
+				Output: "build/ninja.o",
+				Inputs: []string{
+					"ninja.cc",
+					"ninja.h",
+					"eval_env.h",
+					"manifest_parser.h",
+				},
+			},
+		},
+		{
+			name: "EarlyNewlineAndWhitespace",
+			input: ` \
+  out: in`,
+			output: Deps{
+				Output: "out",
+				Inputs: []string{"in"},
+			},
+		},
+		{
+			name: "Continuation",
+			input: `foo.o: \
+  bar.h baz.h
+`,
+			output: Deps{
+				Output: "foo.o",
+				Inputs: []string{"bar.h", "baz.h"},
+			},
+		},
+		{
+			name:  "CarriageReturnContinuation",
+			input: "foo.o: \\\r\n  bar.h baz.h\r\n",
+			output: Deps{
+				Output: "foo.o",
+				Inputs: []string{"bar.h", "baz.h"},
+			},
+		},
+		{
+			name: "BackSlashes",
+			input: `Project\Dir\Build\Release8\Foo\Foo.res : \
+  Dir\Library\Foo.rc \
+  Dir\Library\Version\Bar.h \
+  Dir\Library\Foo.ico \
+  Project\Thing\Bar.tlb \
+`,
+			output: Deps{
+				Output: `Project\Dir\Build\Release8\Foo\Foo.res`,
+				Inputs: []string{
+					`Dir\Library\Foo.rc`,
+					`Dir\Library\Version\Bar.h`,
+					`Dir\Library\Foo.ico`,
+					`Project\Thing\Bar.tlb`,
+				},
+			},
+		},
+		{
+			name:  "Spaces",
+			input: `a\ bc\ def:   a\ b c d`,
+			output: Deps{
+				Output: `a bc def`,
+				Inputs: []string{"a b", "c", "d"},
+			},
+		},
+		{
+			name:  "Escapes",
+			input: `\!\@\#$$\%\^\&\\:`,
+			output: Deps{
+				Output: `\!\@#$\%\^\&\`,
+			},
+		},
+		{
+			name: "SpecialChars",
+			// Ninja includes a number of '=', but our parser can't handle that,
+			// since it sees the equals and switches over to assuming it's an
+			// assignment.
+			//
+			// We don't have any files in our tree that contain an '=' character,
+			// and Kati can't handle parsing this either, so for now I'm just
+			// going to remove all the '=' characters below.
+			//
+			// It looks like make will only do this for the first
+			// dependency, but not later dependencies.
+			input: `C\:/Program\ Files\ (x86)/Microsoft\ crtdefs.h: \
+ en@quot.header~ t+t-x!1 \
+ openldap/slapd.d/cnconfig/cnschema/cn{0}core.ldif \
+ Fu` + "\303\244ball",
+			output: Deps{
+				Output: "C:/Program Files (x86)/Microsoft crtdefs.h",
+				Inputs: []string{
+					"en@quot.header~",
+					"t+t-x!1",
+					"openldap/slapd.d/cnconfig/cnschema/cn{0}core.ldif",
+					"Fu\303\244ball",
+				},
+			},
+		},
+		// Ninja's UnifyMultipleOutputs and RejectMultipleDifferentOutputs tests have been omitted,
+		// since we don't want the same behavior.
+
+		// Our own tests
+		{
+			name: "Multiple outputs",
+			input: `a b: c
+a: d
+b: e`,
+			output: Deps{
+				Output: "b",
+				Inputs: []string{
+					"c",
+					"d",
+					"e",
+				},
+			},
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			out, err := Parse("test.d", bytes.NewBufferString(tc.input))
+			if err != tc.err {
+				t.Fatalf("Unexpected error: %v (expected %v)", err, tc.err)
+			}
+
+			if out.Output != tc.output.Output {
+				t.Errorf("output file doesn't match:\n"+
+					" str: %#v\n"+
+					"want: %#v\n"+
+					" got: %#v", tc.input, tc.output.Output, out.Output)
+			}
+
+			matches := true
+			if len(out.Inputs) != len(tc.output.Inputs) {
+				matches = false
+			} else {
+				for i := range out.Inputs {
+					if out.Inputs[i] != tc.output.Inputs[i] {
+						matches = false
+					}
+				}
+			}
+			if !matches {
+				t.Errorf("input files don't match:\n"+
+					" str: %#v\n"+
+					"want: %#v\n"+
+					" got: %#v", tc.input, tc.output.Inputs, out.Inputs)
+			}
+		})
+	}
+}
+
+func BenchmarkParsing(b *testing.B) {
+	// Write it out to a file to most closely match ninja's perftest
+	tmpfile, err := ioutil.TempFile("", "depfile")
+	if err != nil {
+		b.Fatal("Failed to create temp file:", err)
+	}
+	defer os.Remove(tmpfile.Name())
+	_, err = io.WriteString(tmpfile, `out/soong/.intermediates/external/ninja/ninja/linux_glibc_x86_64/obj/external/ninja/src/ninja.o: \
+  external/ninja/src/ninja.cc external/libcxx/include/errno.h \
+  external/libcxx/include/__config \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/features.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/predefs.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/sys/cdefs.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/wordsize.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/gnu/stubs.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/errno.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/errno.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/linux/errno.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/asm/errno.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/asm-generic/errno.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/asm-generic/errno-base.h \
+  external/libcxx/include/limits.h \
+  prebuilts/clang/host/linux-x86/clang-4639204/lib64/clang/6.0.1/include/limits.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/limits.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/posix1_lim.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/local_lim.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/linux/limits.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/posix2_lim.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/xopen_lim.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/stdio_lim.h \
+  external/libcxx/include/stdio.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/stdio.h \
+  external/libcxx/include/stddef.h \
+  prebuilts/clang/host/linux-x86/clang-4639204/lib64/clang/6.0.1/include/stddef.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/types.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/typesizes.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/libio.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/_G_config.h \
+  external/libcxx/include/wchar.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/wchar.h \
+  prebuilts/clang/host/linux-x86/clang-4639204/lib64/clang/6.0.1/include/stdarg.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/sys_errlist.h \
+  external/libcxx/include/stdlib.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/stdlib.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/waitflags.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/waitstatus.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/endian.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/endian.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/byteswap.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/xlocale.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/sys/types.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/time.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/sys/select.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/select.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/sigset.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/time.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/select2.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/sys/sysmacros.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/alloca.h \
+  external/libcxx/include/string.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/string.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/getopt.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/unistd.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/posix_opt.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/environments.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/confname.h \
+  external/ninja/src/browse.h external/ninja/src/build.h \
+  external/libcxx/include/cstdio external/libcxx/include/map \
+  external/libcxx/include/__tree external/libcxx/include/iterator \
+  external/libcxx/include/iosfwd \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/wchar.h \
+  external/libcxx/include/__functional_base \
+  external/libcxx/include/type_traits external/libcxx/include/cstddef \
+  prebuilts/clang/host/linux-x86/clang-4639204/lib64/clang/6.0.1/include/__stddef_max_align_t.h \
+  external/libcxx/include/__nullptr external/libcxx/include/typeinfo \
+  external/libcxx/include/exception external/libcxx/include/cstdlib \
+  external/libcxx/include/cstdint external/libcxx/include/stdint.h \
+  prebuilts/clang/host/linux-x86/clang-4639204/lib64/clang/6.0.1/include/stdint.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/stdint.h \
+  external/libcxx/include/new external/libcxx/include/utility \
+  external/libcxx/include/__tuple \
+  external/libcxx/include/initializer_list \
+  external/libcxx/include/cstring external/libcxx/include/__debug \
+  external/libcxx/include/memory external/libcxx/include/limits \
+  external/libcxx/include/__undef_macros external/libcxx/include/tuple \
+  external/libcxx/include/stdexcept external/libcxx/include/cassert \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/assert.h \
+  external/libcxx/include/atomic external/libcxx/include/algorithm \
+  external/libcxx/include/functional external/libcxx/include/queue \
+  external/libcxx/include/deque external/libcxx/include/__split_buffer \
+  external/libcxx/include/vector external/libcxx/include/__bit_reference \
+  external/libcxx/include/climits external/libcxx/include/set \
+  external/libcxx/include/string external/libcxx/include/string_view \
+  external/libcxx/include/__string external/libcxx/include/cwchar \
+  external/libcxx/include/cwctype external/libcxx/include/cctype \
+  external/libcxx/include/ctype.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/ctype.h \
+  external/libcxx/include/wctype.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/wctype.h \
+  external/ninja/src/graph.h external/ninja/src/eval_env.h \
+  external/ninja/src/string_piece.h external/ninja/src/timestamp.h \
+  external/ninja/src/util.h external/ninja/src/exit_status.h \
+  external/ninja/src/line_printer.h external/ninja/src/metrics.h \
+  external/ninja/src/build_log.h external/ninja/src/hash_map.h \
+  external/libcxx/include/unordered_map \
+  external/libcxx/include/__hash_table external/libcxx/include/cmath \
+  external/libcxx/include/math.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/math.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/huge_val.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/huge_valf.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/huge_vall.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/inf.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/nan.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/mathdef.h \
+  prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot/usr/include/x86_64-linux-gnu/bits/mathcalls.h \
+  external/ninja/src/deps_log.h external/ninja/src/clean.h \
+  external/ninja/src/debug_flags.h external/ninja/src/disk_interface.h \
+  external/ninja/src/graphviz.h external/ninja/src/manifest_parser.h \
+  external/ninja/src/lexer.h external/ninja/src/state.h \
+  external/ninja/src/version.h`)
+	tmpfile.Close()
+	if err != nil {
+		b.Fatal("Failed to write dep file:", err)
+	}
+	b.ResetTimer()
+
+	for n := 0; n < b.N; n++ {
+		depfile, err := ioutil.ReadFile(tmpfile.Name())
+		if err != nil {
+			b.Fatal("Failed to read dep file:", err)
+		}
+
+		_, err = Parse(tmpfile.Name(), bytes.NewBuffer(depfile))
+		if err != nil {
+			b.Fatal("Failed to parse:", err)
+		}
+	}
+}
+
+func TestDepPrint(t *testing.T) {
+	testCases := []struct {
+		name   string
+		input  Deps
+		output string
+	}{
+		{
+			name: "Empty",
+			input: Deps{
+				Output: "a",
+			},
+			output: "a:",
+		},
+		{
+			name: "Basic",
+			input: Deps{
+				Output: "a",
+				Inputs: []string{"b", "c"},
+			},
+			output: "a: b c",
+		},
+		{
+			name: "Escapes",
+			input: Deps{
+				Output: `\!\@#$\%\^\&\`,
+			},
+			output: `\\!\\@\#$$\\%\\^\\&\\:`,
+		},
+		{
+			name: "Spaces",
+			input: Deps{
+				Output: "a b",
+				Inputs: []string{"c d", "e f "},
+			},
+			output: `a\ b: c\ d e\ f\ `,
+		},
+		{
+			name: "SpecialChars",
+			input: Deps{
+				Output: "C:/Program Files (x86)/Microsoft crtdefs.h",
+				Inputs: []string{
+					"en@quot.header~",
+					"t+t-x!1",
+					"openldap/slapd.d/cnconfig/cnschema/cn{0}core.ldif",
+					"Fu\303\244ball",
+				},
+			},
+			output: `C\:/Program\ Files\ (x86)/Microsoft\ crtdefs.h: en@quot.header~ t+t-x!1 openldap/slapd.d/cnconfig/cnschema/cn{0}core.ldif Fu` + "\303\244ball",
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			out := tc.input.Print()
+			outStr := string(out)
+			want := tc.output + "\n"
+
+			if outStr != want {
+				t.Errorf("output doesn't match:\nwant:%q\n got:%q", want, outStr)
+			}
+		})
+	}
+}
diff --git a/cmd/dep_fixer/main.go b/cmd/dep_fixer/main.go
new file mode 100644
index 0000000..bac3772
--- /dev/null
+++ b/cmd/dep_fixer/main.go
@@ -0,0 +1,67 @@
+// Copyright 2018 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// This tool reads "make"-like dependency files, and outputs a canonical version
+// that can be used by ninja. Ninja doesn't support multiple output files (even
+// though it doesn't care what the output file is, or whether it matches what is
+// expected).
+package main
+
+import (
+	"bytes"
+	"flag"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"os"
+)
+
+func main() {
+	flag.Usage = func() {
+		fmt.Fprintf(os.Stderr, "Usage: %s <depfile.d>")
+		flag.PrintDefaults()
+	}
+	output := flag.String("o", "", "Optional output file (defaults to rewriting source if necessary)")
+	flag.Parse()
+
+	if flag.NArg() != 1 {
+		log.Fatal("Expected a single file as an argument")
+	}
+
+	old, err := ioutil.ReadFile(flag.Arg(0))
+	if err != nil {
+		log.Fatalf("Error opening %q: %v", flag.Arg(0), err)
+	}
+
+	deps, err := Parse(flag.Arg(0), bytes.NewBuffer(append([]byte(nil), old...)))
+	if err != nil {
+		log.Fatalf("Failed to parse: %v", err)
+	}
+
+	new := deps.Print()
+
+	if *output == "" || *output == flag.Arg(0) {
+		if !bytes.Equal(old, new) {
+			err := ioutil.WriteFile(flag.Arg(0), new, 0666)
+			if err != nil {
+				log.Fatalf("Failed to write: %v", err)
+			}
+		}
+	} else {
+		err := ioutil.WriteFile(*output, new, 0666)
+		if err != nil {
+			log.Fatalf("Failed to write to %q: %v", *output, err)
+		}
+	}
+}
diff --git a/cmd/multiproduct_kati/main.go b/cmd/multiproduct_kati/main.go
index 06c5626..ab82963 100644
--- a/cmd/multiproduct_kati/main.go
+++ b/cmd/multiproduct_kati/main.go
@@ -255,6 +255,11 @@
 
 	setMaxFiles(log)
 
+	finder := build.NewSourceFinder(buildCtx, config)
+	defer finder.Shutdown()
+
+	build.FindSources(buildCtx, config, finder)
+
 	vars, err := build.DumpMakeVars(buildCtx, config, nil, []string{"all_named_products"})
 	if err != nil {
 		log.Fatal(err)
@@ -303,9 +308,6 @@
 	var wg sync.WaitGroup
 	productConfigs := make(chan Product, len(products))
 
-	finder := build.NewSourceFinder(buildCtx, config)
-	defer finder.Shutdown()
-
 	// Run the product config for every product in parallel
 	for _, product := range products {
 		wg.Add(1)
diff --git a/java/aar.go b/java/aar.go
index 9e5cddb..66f1cab 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -150,8 +150,8 @@
 		if ctx.ModuleName() == "framework-res" {
 			// Some builds set AppsDefaultVersionName() to include the build number ("O-123456").  aapt2 copies the
 			// version name of framework-res into app manifests as compileSdkVersionCodename, which confuses things
-			// if it contains the build number.  Use the DefaultAppTargetSdk instead.
-			versionName = ctx.Config().DefaultAppTargetSdk()
+			// if it contains the build number.  Use the PlatformVersionName instead.
+			versionName = ctx.Config().PlatformVersionName()
 		} else {
 			versionName = ctx.Config().AppsDefaultVersionName()
 		}
diff --git a/java/androidmk.go b/java/androidmk.go
index b168f2c..88dc6ef 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -286,26 +286,52 @@
 				if ddoc.Javadoc.stubsSrcJar != nil {
 					fmt.Fprintln(w, "LOCAL_DROIDDOC_STUBS_SRCJAR := ", ddoc.Javadoc.stubsSrcJar.String())
 				}
+				if ddoc.checkCurrentApiTimestamp != nil {
+					fmt.Fprintln(w, ".PHONY:", ddoc.Name()+"-check-current-api")
+					fmt.Fprintln(w, ddoc.Name()+"-check-current-api:",
+						ddoc.checkCurrentApiTimestamp.String())
+
+					fmt.Fprintln(w, ".PHONY: checkapi")
+					fmt.Fprintln(w, "checkapi:",
+						ddoc.checkCurrentApiTimestamp.String())
+
+					fmt.Fprintln(w, ".PHONY: droidcore")
+					fmt.Fprintln(w, "droidcore: checkapi")
+				}
+				if ddoc.updateCurrentApiTimestamp != nil {
+					fmt.Fprintln(w, ".PHONY:", ddoc.Name(), "-update-current-api")
+					fmt.Fprintln(w, ddoc.Name()+"-update-current-api:",
+						ddoc.updateCurrentApiTimestamp.String())
+
+					fmt.Fprintln(w, ".PHONY: update-api")
+					fmt.Fprintln(w, "update-api:",
+						ddoc.updateCurrentApiTimestamp.String())
+				}
+				if ddoc.checkLastReleasedApiTimestamp != nil {
+					fmt.Fprintln(w, ".PHONY:", ddoc.Name()+"-check-last-released-api")
+					fmt.Fprintln(w, ddoc.Name()+"-check-last-released-api:",
+						ddoc.checkLastReleasedApiTimestamp.String())
+				}
 				apiFilePrefix := "INTERNAL_PLATFORM_"
 				if String(ddoc.properties.Api_tag_name) != "" {
 					apiFilePrefix += String(ddoc.properties.Api_tag_name) + "_"
 				}
-				if String(ddoc.properties.Api_filename) != "" {
+				if ddoc.apiFile != nil {
 					fmt.Fprintln(w, apiFilePrefix+"API_FILE := ", ddoc.apiFile.String())
 				}
-				if String(ddoc.properties.Private_api_filename) != "" {
+				if ddoc.privateApiFile != nil {
 					fmt.Fprintln(w, apiFilePrefix+"PRIVATE_API_FILE := ", ddoc.privateApiFile.String())
 				}
-				if String(ddoc.properties.Private_dex_api_filename) != "" {
+				if ddoc.privateDexApiFile != nil {
 					fmt.Fprintln(w, apiFilePrefix+"PRIVATE_DEX_API_FILE := ", ddoc.privateDexApiFile.String())
 				}
-				if String(ddoc.properties.Removed_api_filename) != "" {
+				if ddoc.removedApiFile != nil {
 					fmt.Fprintln(w, apiFilePrefix+"REMOVED_API_FILE := ", ddoc.removedApiFile.String())
 				}
-				if String(ddoc.properties.Removed_dex_api_filename) != "" {
+				if ddoc.removedDexApiFile != nil {
 					fmt.Fprintln(w, apiFilePrefix+"REMOVED_DEX_API_FILE := ", ddoc.removedDexApiFile.String())
 				}
-				if String(ddoc.properties.Exact_api_filename) != "" {
+				if ddoc.exactApiFile != nil {
 					fmt.Fprintln(w, apiFilePrefix+"EXACT_API_FILE := ", ddoc.exactApiFile.String())
 				}
 			},
diff --git a/java/config/config.go b/java/config/config.go
index 6633f79..d44315c 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -90,6 +90,7 @@
 	pctx.HostBinToolVariable("MergeZipsCmd", "merge_zips")
 	pctx.HostBinToolVariable("Zip2ZipCmd", "zip2zip")
 	pctx.HostBinToolVariable("ZipSyncCmd", "zipsync")
+	pctx.HostBinToolVariable("ApiCheckCmd", "apicheck")
 	pctx.VariableFunc("DxCmd", func(ctx android.PackageVarContext) string {
 		config := ctx.Config()
 		if config.IsEnvFalse("USE_D8") {
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 07042a1..b34c393 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -45,6 +45,24 @@
 		},
 		"outDir", "srcJarDir", "stubsDir", "srcJars", "opts",
 		"bootclasspathArgs", "classpathArgs", "sourcepath", "docZip")
+
+	apiCheck = pctx.AndroidStaticRule("apiCheck",
+		blueprint.RuleParams{
+			Command: `( ${config.ApiCheckCmd} -JXmx1024m -J"classpath $classpath" $opts ` +
+				`$apiFile $apiFileToCheck $removedApiFile $removedApiFileToCheck ` +
+				`&& touch $out ) || (echo -e "$msg" ; exit 38)`,
+			CommandDeps: []string{
+				"${config.ApiCheckCmd}",
+			},
+		},
+		"classpath", "opts", "apiFile", "apiFileToCheck", "removedApiFile", "removedApiFileToCheck", "msg")
+
+	updateApi = pctx.AndroidStaticRule("updateApi",
+		blueprint.RuleParams{
+			Command: `( ( cp -f $apiFileToCheck $apiFile && cp -f $removedApiFileToCheck $removedApiFile ) ` +
+				`&& touch $out ) || (echo failed to update public API ; exit 38)`,
+		},
+		"apiFile", "apiFileToCheck", "removedApiFile", "removedApiFileToCheck")
 )
 
 func init() {
@@ -94,6 +112,20 @@
 	Sdk_version *string `android:"arch_variant"`
 }
 
+type ApiToCheck struct {
+	// path to the API txt file that the new API extracted from source code is checked
+	// against. The path can be local to the module or from other module (via :module syntax).
+	Api_file *string
+
+	// path to the API txt file that the new @removed API extractd from source code is
+	// checked against. The path can be local to the module or from other module (via
+	// :module syntax).
+	Removed_api_file *string
+
+	// Arguments to the apicheck tool.
+	Args *string
+}
+
 type DroiddocProperties struct {
 	// directory relative to top of the source tree that contains doc templates files.
 	Custom_template *string
@@ -157,6 +189,12 @@
 
 	// if set to false, don't allow droiddoc to generate stubs source files. Defaults to true.
 	Create_stubs *bool
+
+	Check_api struct {
+		Last_released ApiToCheck
+
+		Current ApiToCheck
+	}
 }
 
 type Javadoc struct {
@@ -189,6 +227,10 @@
 	removedApiFile    android.WritablePath
 	removedDexApiFile android.WritablePath
 	exactApiFile      android.WritablePath
+
+	checkCurrentApiTimestamp      android.WritablePath
+	updateCurrentApiTimestamp     android.WritablePath
+	checkLastReleasedApiTimestamp android.WritablePath
 }
 
 func InitDroiddocModule(module android.DefaultableModule, hod android.HostOrDeviceSupported) {
@@ -420,6 +462,32 @@
 	})
 }
 
+func (d *Droiddoc) checkCurrentApi() bool {
+	if String(d.properties.Check_api.Current.Api_file) != "" &&
+		String(d.properties.Check_api.Current.Removed_api_file) != "" {
+		return true
+	} else if String(d.properties.Check_api.Current.Api_file) != "" {
+		panic("check_api.current.removed_api_file: has to be non empty!")
+	} else if String(d.properties.Check_api.Current.Removed_api_file) != "" {
+		panic("check_api.current.api_file: has to be non empty!")
+	}
+
+	return false
+}
+
+func (d *Droiddoc) checkLastReleasedApi() bool {
+	if String(d.properties.Check_api.Last_released.Api_file) != "" &&
+		String(d.properties.Check_api.Last_released.Removed_api_file) != "" {
+		return true
+	} else if String(d.properties.Check_api.Last_released.Api_file) != "" {
+		panic("check_api.last_released.removed_api_file: has to be non empty!")
+	} else if String(d.properties.Check_api.Last_released.Removed_api_file) != "" {
+		panic("check_api.last_released.api_file: has to be non empty!")
+	}
+
+	return false
+}
+
 func (d *Droiddoc) DepsMutator(ctx android.BottomUpMutatorContext) {
 	d.Javadoc.addDeps(ctx)
 
@@ -435,6 +503,16 @@
 
 	// knowntags may contain filegroup or genrule.
 	android.ExtractSourcesDeps(ctx, d.properties.Knowntags)
+
+	if d.checkCurrentApi() {
+		android.ExtractSourceDeps(ctx, d.properties.Check_api.Current.Api_file)
+		android.ExtractSourceDeps(ctx, d.properties.Check_api.Current.Removed_api_file)
+	}
+
+	if d.checkLastReleasedApi() {
+		android.ExtractSourceDeps(ctx, d.properties.Check_api.Last_released.Api_file)
+		android.ExtractSourceDeps(ctx, d.properties.Check_api.Last_released.Removed_api_file)
+	}
 }
 
 func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -547,12 +625,19 @@
 	}
 
 	var implicitOutputs android.WritablePaths
-	if String(d.properties.Api_filename) != "" {
-		d.apiFile = android.PathForModuleOut(ctx, String(d.properties.Api_filename))
+
+	if d.checkCurrentApi() || d.checkLastReleasedApi() || String(d.properties.Api_filename) != "" {
+		d.apiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_api.txt")
 		args = args + " -api " + d.apiFile.String()
 		implicitOutputs = append(implicitOutputs, d.apiFile)
 	}
 
+	if d.checkCurrentApi() || d.checkLastReleasedApi() || String(d.properties.Removed_api_filename) != "" {
+		d.removedApiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_removed.txt")
+		args = args + " -removedApi " + d.removedApiFile.String()
+		implicitOutputs = append(implicitOutputs, d.removedApiFile)
+	}
+
 	if String(d.properties.Private_api_filename) != "" {
 		d.privateApiFile = android.PathForModuleOut(ctx, String(d.properties.Private_api_filename))
 		args = args + " -privateApi " + d.privateApiFile.String()
@@ -565,12 +650,6 @@
 		implicitOutputs = append(implicitOutputs, d.privateDexApiFile)
 	}
 
-	if String(d.properties.Removed_api_filename) != "" {
-		d.removedApiFile = android.PathForModuleOut(ctx, String(d.properties.Removed_api_filename))
-		args = args + " -removedApi " + d.removedApiFile.String()
-		implicitOutputs = append(implicitOutputs, d.removedApiFile)
-	}
-
 	if String(d.properties.Removed_dex_api_filename) != "" {
 		d.removedDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Removed_dex_api_filename))
 		args = args + " -removedDexApi " + d.removedDexApiFile.String()
@@ -624,6 +703,91 @@
 			"docZip":            d.Javadoc.docZip.String(),
 		},
 	})
+
+	java8Home := ctx.Config().Getenv("ANDROID_JAVA8_HOME")
+
+	checkApiClasspath := classpath{jsilver, doclava, android.PathForSource(ctx, java8Home, "lib/tools.jar")}
+
+	if d.checkCurrentApi() && !ctx.Config().IsPdkBuild() {
+		d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "check_current_api.timestamp")
+
+		apiFile := ctx.ExpandSource(String(d.properties.Check_api.Current.Api_file),
+			"check_api.current.api_file")
+		removedApiFile := ctx.ExpandSource(String(d.properties.Check_api.Current.Removed_api_file),
+			"check_api.current_removed_api_file")
+
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        apiCheck,
+			Description: "Current API check",
+			Output:      d.checkCurrentApiTimestamp,
+			Inputs:      nil,
+			Implicits: append(android.Paths{apiFile, removedApiFile, d.apiFile, d.removedApiFile},
+				checkApiClasspath...),
+			Args: map[string]string{
+				"classpath":             checkApiClasspath.FormJavaClassPath(""),
+				"opts":                  String(d.properties.Check_api.Current.Args),
+				"apiFile":               apiFile.String(),
+				"apiFileToCheck":        d.apiFile.String(),
+				"removedApiFile":        removedApiFile.String(),
+				"removedApiFileToCheck": d.removedApiFile.String(),
+				"msg": fmt.Sprintf(`\n******************************\n`+
+					`You have tried to change the API from what has been previously approved.\n\n`+
+					`To make these errors go away, you have two choices:\n`+
+					`   1. You can add '@hide' javadoc comments to the methods, etc. listed in the\n`+
+					`      errors above.\n\n`+
+					`   2. You can update current.txt by executing the following command:\n`+
+					`         make %s-update-current-api\n\n`+
+					`      To submit the revised current.txt to the main Android repository,\n`+
+					`      you will need approval.\n`+
+					`******************************\n`, ctx.ModuleName()),
+			},
+		})
+
+		d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "update_current_api.timestamp")
+
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        updateApi,
+			Description: "update current API",
+			Output:      d.updateCurrentApiTimestamp,
+			Implicits:   append(android.Paths{}, apiFile, removedApiFile, d.apiFile, d.removedApiFile),
+			Args: map[string]string{
+				"apiFile":               apiFile.String(),
+				"apiFileToCheck":        d.apiFile.String(),
+				"removedApiFile":        removedApiFile.String(),
+				"removedApiFileToCheck": d.removedApiFile.String(),
+			},
+		})
+	}
+
+	if d.checkLastReleasedApi() && !ctx.Config().IsPdkBuild() {
+		d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, "check_last_released_api.timestamp")
+
+		apiFile := ctx.ExpandSource(String(d.properties.Check_api.Last_released.Api_file),
+			"check_api.last_released.api_file")
+		removedApiFile := ctx.ExpandSource(String(d.properties.Check_api.Last_released.Removed_api_file),
+			"check_api.last_released.removed_api_file")
+
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        apiCheck,
+			Description: "Last Released API check",
+			Output:      d.checkLastReleasedApiTimestamp,
+			Inputs:      nil,
+			Implicits: append(android.Paths{apiFile, removedApiFile, d.apiFile, d.removedApiFile},
+				checkApiClasspath...),
+			Args: map[string]string{
+				"classpath":             checkApiClasspath.FormJavaClassPath(""),
+				"opts":                  String(d.properties.Check_api.Last_released.Args),
+				"apiFile":               apiFile.String(),
+				"apiFileToCheck":        d.apiFile.String(),
+				"removedApiFile":        removedApiFile.String(),
+				"removedApiFileToCheck": d.removedApiFile.String(),
+				"msg": `\n******************************\n` +
+					`You have tried to change the API from what has been previously released in\n` +
+					`an SDK.  Please fix the errors listed above.\n` +
+					`******************************\n`,
+			},
+		})
+	}
 }
 
 var droiddocTemplateTag = dependencyTag{name: "droiddoc-template"}
diff --git a/java/java_test.go b/java/java_test.go
index ea52496..fe1c3d7 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -84,10 +84,12 @@
 	ctx.RegisterModuleType("droiddoc_host", android.ModuleFactoryAdaptor(DroiddocHostFactory))
 	ctx.RegisterModuleType("droiddoc_template", android.ModuleFactoryAdaptor(DroiddocTemplateFactory))
 	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.RegisterPreSingletonType("overlay", android.SingletonFactoryAdaptor(OverlaySingletonFactory))
@@ -141,19 +143,25 @@
 	}
 
 	mockFS := map[string][]byte{
-		"Android.bp":     []byte(bp),
-		"a.java":         nil,
-		"b.java":         nil,
-		"c.java":         nil,
-		"b.kt":           nil,
-		"a.jar":          nil,
-		"b.jar":          nil,
-		"java-res/a/a":   nil,
-		"java-res/b/b":   nil,
-		"java-res2/a":    nil,
-		"java-fg/a.java": nil,
-		"java-fg/b.java": nil,
-		"java-fg/c.java": nil,
+		"Android.bp":             []byte(bp),
+		"a.java":                 nil,
+		"b.java":                 nil,
+		"c.java":                 nil,
+		"b.kt":                   nil,
+		"a.jar":                  nil,
+		"b.jar":                  nil,
+		"java-res/a/a":           nil,
+		"java-res/b/b":           nil,
+		"java-res2/a":            nil,
+		"java-fg/a.java":         nil,
+		"java-fg/b.java":         nil,
+		"java-fg/c.java":         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/14/public/android.jar":         nil,
 		"prebuilts/sdk/14/public/framework.aidl":      nil,
@@ -163,6 +171,19 @@
 		"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/foo.txt":         nil,
+		"prebuilts/sdk/28/system/api/foo.txt":         nil,
+		"prebuilts/sdk/28/test/api/foo.txt":           nil,
+		"prebuilts/sdk/28/public/api/foo-removed.txt": nil,
+		"prebuilts/sdk/28/system/api/foo-removed.txt": nil,
+		"prebuilts/sdk/28/test/api/foo-removed.txt":   nil,
+		"prebuilts/sdk/28/public/api/bar.txt":         nil,
+		"prebuilts/sdk/28/system/api/bar.txt":         nil,
+		"prebuilts/sdk/28/test/api/bar.txt":           nil,
+		"prebuilts/sdk/28/public/api/bar-removed.txt": nil,
+		"prebuilts/sdk/28/system/api/bar-removed.txt": nil,
+		"prebuilts/sdk/28/test/api/bar-removed.txt":   nil,
+		"prebuilts/sdk/Android.bp":                    []byte(`prebuilt_apis { name: "prebuilt_apis",}`),
 
 		// For framework-res, which is an implicit dependency for framework
 		"AndroidManifest.xml":                   nil,
@@ -175,6 +196,7 @@
 
 		"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,
@@ -195,7 +217,7 @@
 
 func run(t *testing.T, ctx *android.TestContext, config android.Config) {
 	t.Helper()
-	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp", "prebuilts/sdk/Android.bp"})
 	android.FailIfErrored(t, errs)
 	_, errs = ctx.PrepareBuildActions(config)
 	android.FailIfErrored(t, errs)
@@ -1037,10 +1059,15 @@
 	ctx.ModuleForTests("foo", "android_common")
 	ctx.ModuleForTests("foo"+sdkStubsLibrarySuffix, "android_common")
 	ctx.ModuleForTests("foo"+sdkStubsLibrarySuffix+sdkSystemApiSuffix, "android_common")
+	ctx.ModuleForTests("foo"+sdkStubsLibrarySuffix+sdkTestApiSuffix, "android_common")
 	ctx.ModuleForTests("foo"+sdkDocsSuffix, "android_common")
 	ctx.ModuleForTests("foo"+sdkDocsSuffix+sdkSystemApiSuffix, "android_common")
+	ctx.ModuleForTests("foo"+sdkDocsSuffix+sdkTestApiSuffix, "android_common")
 	ctx.ModuleForTests("foo"+sdkImplLibrarySuffix, "android_common")
 	ctx.ModuleForTests("foo"+sdkXmlFileSuffix, "android_common")
+	ctx.ModuleForTests("foo.api.public.28", "")
+	ctx.ModuleForTests("foo.api.system.28", "")
+	ctx.ModuleForTests("foo.api.test.28", "")
 
 	bazJavac := ctx.ModuleForTests("baz", "android_common").Rule("javac")
 	// tests if baz is actually linked to the stubs lib
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
new file mode 100644
index 0000000..50318bb
--- /dev/null
+++ b/java/prebuilt_apis.go
@@ -0,0 +1,140 @@
+// Copyright 2018 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+	"android/soong/android"
+	"sort"
+	"strconv"
+	"strings"
+
+	"github.com/google/blueprint/proptools"
+)
+
+// prebuilt_apis is a meta-module that generates filegroup modules for all
+// API txt files found under the directory where the Android.bp is located.
+// Specificaly, an API file located at ./<ver>/<scope>/api/<module>.txt
+// generates a filegroup module named <module>-api.<scope>.<ver>.
+//
+// It also creates <module>-api.<scope>.latest for the lastest <ver>.
+//
+func init() {
+	android.RegisterModuleType("prebuilt_apis", prebuiltApisFactory)
+
+	android.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.TopDown("prebuilt_apis", prebuiltApisMutator).Parallel()
+	})
+}
+
+type prebuiltApis struct {
+	android.ModuleBase
+}
+
+func (module *prebuiltApis) DepsMutator(ctx android.BottomUpMutatorContext) {
+	// no need to implement
+}
+
+func (module *prebuiltApis) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	// no need to implement
+}
+
+func parseApiFilePath(ctx android.BaseModuleContext, path string) (module string, apiver int, scope string) {
+	elements := strings.Split(path, "/")
+	ver, err := strconv.Atoi(elements[0])
+	if err != nil {
+		ctx.ModuleErrorf("invalid version %q found in path: %q", elements[0], path)
+		return
+	}
+	apiver = ver
+
+	scope = elements[1]
+	if scope != "public" && scope != "system" && scope != "test" {
+		ctx.ModuleErrorf("invalid scope %q found in path: %q", scope, path)
+		return
+	}
+
+	// elements[2] is string literal "api". skipping.
+	module = strings.TrimSuffix(elements[3], ".txt")
+	return
+}
+
+func createFilegroup(mctx android.TopDownMutatorContext, module string, scope string, apiver string, path string) {
+	fgName := module + ".api." + scope + "." + apiver
+	filegroupProps := struct {
+		Name *string
+		Srcs []string
+	}{}
+	filegroupProps.Name = proptools.StringPtr(fgName)
+	filegroupProps.Srcs = []string{path}
+	mctx.CreateModule(android.ModuleFactoryAdaptor(android.FileGroupFactory), &filegroupProps)
+}
+
+func prebuiltApisMutator(mctx android.TopDownMutatorContext) {
+	if _, ok := mctx.Module().(*prebuiltApis); ok {
+		mydir := mctx.ModuleDir() + "/"
+		// <apiver>/<scope>/api/<module>.txt
+		files, err := mctx.GlobWithDeps(mydir+"*/*/api/*.txt", nil)
+		if err != nil {
+			mctx.ModuleErrorf("failed to glob api txt files under %q: %s", mydir, err)
+		}
+		if len(files) == 0 {
+			mctx.ModuleErrorf("no api file found under %q", mydir)
+		}
+
+		// construct a map to find out the latest api file path
+		// for each (<module>, <scope>) pair.
+		type latestApiInfo struct {
+			module string
+			scope  string
+			apiver int
+			path   string
+		}
+		m := make(map[string]latestApiInfo)
+
+		for _, f := range files {
+			// create a filegroup for each api txt file
+			localPath := strings.TrimPrefix(f, mydir)
+			module, apiver, scope := parseApiFilePath(mctx, localPath)
+			createFilegroup(mctx, module, scope, strconv.Itoa(apiver), localPath)
+
+			// find the latest apiver
+			key := module + "." + scope
+			info, ok := m[key]
+			if !ok {
+				m[key] = latestApiInfo{module, scope, apiver, localPath}
+			} else if apiver > info.apiver {
+				info.apiver = apiver
+				info.path = localPath
+			}
+		}
+		// create filegroups for the latest version of (<module>, <scope>) pairs
+		// sort the keys in order to make build.ninja stable
+		keys := make([]string, 0, len(m))
+		for k := range m {
+			keys = append(keys, k)
+		}
+		sort.Strings(keys)
+		for _, k := range keys {
+			info := m[k]
+			createFilegroup(mctx, info.module, info.scope, "latest", info.path)
+		}
+	}
+}
+
+func prebuiltApisFactory() android.Module {
+	module := &prebuiltApis{}
+	android.InitAndroidModule(module)
+	return module
+}
diff --git a/java/proto.go b/java/proto.go
index cfd733a..3ec2e8a 100644
--- a/java/proto.go
+++ b/java/proto.go
@@ -30,12 +30,14 @@
 	proto = pctx.AndroidStaticRule("protoc",
 		blueprint.RuleParams{
 			Command: `rm -rf $out.tmp && mkdir -p $out.tmp && ` +
-				`$protocCmd $protoOut=$protoOutParams:$out.tmp -I $protoBase $protoFlags $in && ` +
+				`$protocCmd $protoOut=$protoOutParams:$out.tmp --dependency_out=$out.d -I $protoBase $protoFlags $in && ` +
 				`${config.SoongZipCmd} -jar -o $out -C $out.tmp -D $out.tmp && rm -rf $out.tmp`,
 			CommandDeps: []string{
 				"$protocCmd",
 				"${config.SoongZipCmd}",
 			},
+			Depfile: "${out}.d",
+			Deps:    blueprint.DepsGCC,
 		}, "protoBase", "protoFlags", "protoOut", "protoOutParams")
 )
 
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 703401c..ba121ab 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -67,11 +67,9 @@
 // classpath at runtime if requested via <uses-library>.
 //
 // TODO: these are big features that are currently missing
-// 1) check for API consistency
-// 2) install stubs libs as the dist artifacts
-// 3) ensuring that apps have appropriate <uses-library> tag
-// 4) disallowing linking to the runtime shared lib
-// 5) HTML generation
+// 1) ensuring that apps have appropriate <uses-library> tag
+// 2) disallowing linking to the runtime shared lib
+// 3) HTML generation
 
 func init() {
 	android.RegisterModuleType("java_sdk_library", sdkLibraryFactory)
@@ -155,15 +153,31 @@
 }
 
 func (module *sdkLibrary) AndroidMk() android.AndroidMkData {
-	// Create a phony module that installs the impl library, for the case when this lib is
-	// in PRODUCT_PACKAGES.
 	return android.AndroidMkData{
 		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
+			// Create a phony module that installs the impl library, for the case when this lib is
+			// in PRODUCT_PACKAGES.
 			fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
 			fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
 			fmt.Fprintln(w, "LOCAL_MODULE :=", name)
 			fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES := "+module.implName())
 			fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
+			// Create dist rules to install the stubs libs to the dist dir
+			if len(module.publicApiStubsPath) == 1 {
+				fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
+					module.publicApiStubsPath.Strings()[0]+
+					":"+path.Join("apistubs", "public", module.BaseModuleName()+".jar")+")")
+			}
+			if len(module.systemApiStubsPath) == 1 {
+				fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
+					module.systemApiStubsPath.Strings()[0]+
+					":"+path.Join("apistubs", "system", module.BaseModuleName()+".jar")+")")
+			}
+			if len(module.testApiStubsPath) == 1 {
+				fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
+					module.testApiStubsPath.Strings()[0]+
+					":"+path.Join("apistubs", "test", module.BaseModuleName()+".jar")+")")
+			}
 		},
 	}
 }
@@ -245,21 +259,32 @@
 	return apiTagName
 }
 
-// returns the path (relative to this module) to the API txt file. Files are located
-// ./<api_dir>/<api_level>.txt where <api_level> is either current, system-current, removed,
-// or system-removed.
-func (module *sdkLibrary) apiFilePath(apiLevel string, apiScope apiScope) string {
-	apiDir := "api"
-	apiFile := apiLevel
+func (module *sdkLibrary) latestApiFilegroupName(apiScope apiScope) string {
+	name := ":" + module.BaseModuleName() + ".api."
 	switch apiScope {
+	case apiScopePublic:
+		name = name + "public"
 	case apiScopeSystem:
-		apiFile = "system-" + apiFile
+		name = name + "system"
 	case apiScopeTest:
-		apiFile = "test-" + apiFile
+		name = name + "test"
 	}
-	apiFile = apiFile + ".txt"
+	name = name + ".latest"
+	return name
+}
 
-	return path.Join(apiDir, apiFile)
+func (module *sdkLibrary) latestRemovedApiFilegroupName(apiScope apiScope) string {
+	name := ":" + module.BaseModuleName() + "-removed.api."
+	switch apiScope {
+	case apiScopePublic:
+		name = name + "public"
+	case apiScopeSystem:
+		name = name + "system"
+	case apiScopeTest:
+		name = name + "test"
+	}
+	name = name + ".latest"
+	return name
 }
 
 // Creates a static java library that has API stubs
@@ -316,6 +341,10 @@
 		Api_tag_name            *string
 		Api_filename            *string
 		Removed_api_filename    *string
+		Check_api               struct {
+			Current       ApiToCheck
+			Last_released ApiToCheck
+		}
 	}{}
 
 	props.Name = proptools.StringPtr(module.docsName(apiScope))
@@ -340,7 +369,6 @@
 	// List of APIs identified from the provided source files are created. They are later
 	// compared against to the not-yet-released (a.k.a current) list of APIs and to the
 	// last-released (a.k.a numbered) list of API.
-	// TODO: If any incompatible change is detected, break the build
 	currentApiFileName := "current.txt"
 	removedApiFileName := "removed.txt"
 	switch apiScope {
@@ -353,12 +381,31 @@
 	}
 	currentApiFileName = path.Join("api", currentApiFileName)
 	removedApiFileName = path.Join("api", removedApiFileName)
+	// TODO(jiyong): remove these three props
 	props.Api_tag_name = proptools.StringPtr(module.apiTagName(apiScope))
-	// Note: the exact names of these two are not important because they are always
-	// referenced by the make variable $(INTERNAL_PLATFORM_<TAG_NAME>_API_FILE)
 	props.Api_filename = proptools.StringPtr(currentApiFileName)
 	props.Removed_api_filename = proptools.StringPtr(removedApiFileName)
 
+	// check against the not-yet-release API
+	props.Check_api.Current.Api_file = proptools.StringPtr(currentApiFileName)
+	props.Check_api.Current.Removed_api_file = proptools.StringPtr(removedApiFileName)
+	// any change is reported as error
+	props.Check_api.Current.Args = proptools.StringPtr("-error 2 -error 3 -error 4 -error 5 " +
+		"-error 6 -error 7 -error 8 -error 9 -error 10 -error 11 -error 12 -error 13 " +
+		"-error 14 -error 15 -error 16 -error 17 -error 18 -error 19 -error 20 " +
+		"-error 21 -error 23 -error 24 -error 25 -error 26 -error 27")
+
+	// check against the latest released API
+	props.Check_api.Last_released.Api_file = proptools.StringPtr(
+		module.latestApiFilegroupName(apiScope))
+	props.Check_api.Last_released.Removed_api_file = proptools.StringPtr(
+		module.latestRemovedApiFilegroupName(apiScope))
+	// backward incompatible changes are reported as error
+	props.Check_api.Last_released.Args = proptools.StringPtr("-hide 2 -hide 3 -hide 4 -hide 5 " +
+		"-hide 6 -hide 24 -hide 25 -hide 26 -hide 27 " +
+		"-error 7 -error 8 -error 9 -error 10 -error 11 -error 12 -error 13 -error 14 " +
+		"-error 15 -error 16 -error 17 -error 18")
+
 	// Include the part of the framework source. This is required for the case when
 	// API class is extending from the framework class. In that case, doclava needs
 	// to know whether the base class is hidden or not. Since that information is
diff --git a/java/support_libraries.go b/java/support_libraries.go
new file mode 100644
index 0000000..320afae
--- /dev/null
+++ b/java/support_libraries.go
@@ -0,0 +1,66 @@
+// Copyright 2018 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+	"sort"
+	"strings"
+
+	"android/soong/android"
+)
+
+func init() {
+	android.RegisterMakeVarsProvider(pctx, supportLibrariesMakeVarsProvider)
+}
+
+func supportLibrariesMakeVarsProvider(ctx android.MakeVarsContext) {
+	var supportAars, supportJars []string
+
+	sctx := ctx.SingletonContext()
+	sctx.VisitAllModules(func(module android.Module) {
+		dir := sctx.ModuleDir(module)
+		switch {
+		case strings.HasPrefix(dir, "prebuilts/sdk/current/extras"),
+			dir == "prebuilts/sdk/current/androidx",
+			dir == "prebuilts/sdk/current/car",
+			dir == "prebuilts/sdk/current/optional",
+			dir == "prebuilts/sdk/current/support":
+			// Support library
+		default:
+			// Not a support library
+			return
+		}
+
+		name := sctx.ModuleName(module)
+		if strings.HasSuffix(name, "-nodeps") {
+			return
+		}
+
+		switch module.(type) {
+		case *AndroidLibrary, *AARImport:
+			supportAars = append(supportAars, name)
+		case *Library, *Import:
+			supportJars = append(supportJars, name)
+		default:
+			sctx.ModuleErrorf(module, "unknown module type %t", module)
+		}
+	})
+
+	sort.Strings(supportAars)
+	sort.Strings(supportJars)
+
+	ctx.Strict("SUPPORT_LIBRARIES_AARS", strings.Join(supportAars, " "))
+	ctx.Strict("SUPPORT_LIBRARIES_JARS", strings.Join(supportJars, " "))
+}
diff --git a/python/proto.go b/python/proto.go
index 82ee3cb..42987fa 100644
--- a/python/proto.go
+++ b/python/proto.go
@@ -29,12 +29,14 @@
 	proto = pctx.AndroidStaticRule("protoc",
 		blueprint.RuleParams{
 			Command: `rm -rf $out.tmp && mkdir -p $out.tmp && ` +
-				`$protocCmd --python_out=$out.tmp -I $protoBase $protoFlags $in && ` +
+				`$protocCmd --python_out=$out.tmp --dependency_out=$out.d -I $protoBase $protoFlags $in && ` +
 				`$parCmd -o $out -P $pkgPath -C $out.tmp -D $out.tmp && rm -rf $out.tmp`,
 			CommandDeps: []string{
 				"$protocCmd",
 				"$parCmd",
 			},
+			Depfile: "${out}.d",
+			Deps:    blueprint.DepsGCC,
 		}, "protoBase", "protoFlags", "pkgPath")
 )
 
diff --git a/scripts/build-ndk-prebuilts.sh b/scripts/build-ndk-prebuilts.sh
index d150451..e3552a0 100755
--- a/scripts/build-ndk-prebuilts.sh
+++ b/scripts/build-ndk-prebuilts.sh
@@ -48,7 +48,7 @@
     "Platform_sdk_version": ${PLATFORM_SDK_VERSION},
     "Platform_version_active_codenames": ${PLATFORM_VERSION_ALL_CODENAMES},
 
-    "DeviceName": "flounder",
+    "DeviceName": "generic_arm64",
     "DeviceArch": "arm64",
     "DeviceArchVariant": "armv8-a",
     "DeviceCpuVariant": "denver64",
diff --git a/ui/build/util.go b/ui/build/util.go
index f698ccd..96088fe 100644
--- a/ui/build/util.go
+++ b/ui/build/util.go
@@ -62,9 +62,24 @@
 func ensureEmptyDirectoriesExist(ctx Context, dirs ...string) {
 	// remove all the directories
 	for _, dir := range dirs {
-		err := os.RemoveAll(dir)
-		if err != nil {
-			ctx.Fatalf("Error removing %s: %q\n", dir, err)
+		seenErr := map[string]bool{}
+		for {
+			err := os.RemoveAll(dir)
+			if err == nil {
+				break
+			}
+
+			if pathErr, ok := err.(*os.PathError); !ok ||
+				dir == pathErr.Path || seenErr[pathErr.Path] {
+
+				ctx.Fatalf("Error removing %s: %q\n", dir, err)
+			} else {
+				seenErr[pathErr.Path] = true
+				err = os.Chmod(filepath.Dir(pathErr.Path), 0700)
+				if err != nil {
+					ctx.Fatal(err)
+				}
+			}
 		}
 	}
 	// recreate all the directories
diff --git a/ui/build/util_test.go b/ui/build/util_test.go
index e85eada..0e0dbdf 100644
--- a/ui/build/util_test.go
+++ b/ui/build/util_test.go
@@ -14,7 +14,41 @@
 
 package build
 
-import "testing"
+import (
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"testing"
+
+	"android/soong/ui/logger"
+)
+
+func TestEnsureEmptyDirs(t *testing.T) {
+	ctx := testContext()
+	defer logger.Recover(func(err error) {
+		t.Error(err)
+	})
+
+	tmpDir, err := ioutil.TempDir("", "")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer func() {
+		err := os.RemoveAll(tmpDir)
+		if err != nil {
+			t.Errorf("Error removing tmpDir: %v", err)
+		}
+	}()
+
+	ensureEmptyDirectoriesExist(ctx, filepath.Join(tmpDir, "a/b"))
+
+	err = os.Chmod(filepath.Join(tmpDir, "a"), 0555)
+	if err != nil {
+		t.Fatalf("Failed to chown: %v", err)
+	}
+
+	ensureEmptyDirectoriesExist(ctx, filepath.Join(tmpDir, "a"))
+}
 
 func TestStripAnsiEscapes(t *testing.T) {
 	testcases := []struct {