Merge "Add bool to control if we need generate stubs src files."
diff --git a/Android.bp b/Android.bp
index ec69df8..ad2ad47 100644
--- a/Android.bp
+++ b/Android.bp
@@ -219,6 +219,7 @@
     srcs: [
         "java/aapt2.go",
         "java/aar.go",
+        "java/android_resources.go",
         "java/androidmk.go",
         "java/app_builder.go",
         "java/app.go",
@@ -229,8 +230,8 @@
         "java/genrule.go",
         "java/jacoco.go",
         "java/java.go",
+        "java/java_resources.go",
         "java/proto.go",
-        "java/resources.go",
         "java/system_modules.go",
     ],
     testSrcs: [
diff --git a/android/config.go b/android/config.go
index b89ae48..7122f48 100644
--- a/android/config.go
+++ b/android/config.go
@@ -629,6 +629,10 @@
 	return c.targetOpenJDK9
 }
 
+func (c *config) UseClangLld() bool {
+	return Bool(c.productVariables.UseClangLld)
+}
+
 func (c *config) ClangTidy() bool {
 	return Bool(c.productVariables.ClangTidy)
 }
diff --git a/android/namespace.go b/android/namespace.go
index 1f8ef5a..0230524 100644
--- a/android/namespace.go
+++ b/android/namespace.go
@@ -255,22 +255,7 @@
 }
 
 func (r *NameResolver) Rename(oldName string, newName string, namespace blueprint.Namespace) []error {
-	oldNs := r.findNamespace(oldName)
-	newNs := r.findNamespace(newName)
-	if oldNs != newNs {
-		return []error{fmt.Errorf("cannot rename %v to %v because the destination is outside namespace %v", oldName, newName, oldNs.Path)}
-	}
-
-	oldName, err := filepath.Rel(oldNs.Path, oldName)
-	if err != nil {
-		panic(err)
-	}
-	newName, err = filepath.Rel(newNs.Path, newName)
-	if err != nil {
-		panic(err)
-	}
-
-	return oldNs.moduleContainer.Rename(oldName, newName, nil)
+	return namespace.(*Namespace).moduleContainer.Rename(oldName, newName, namespace)
 }
 
 // resolve each element of namespace.importedNamespaceNames and put the result in namespace.visibleNamespaces
diff --git a/android/namespace_test.go b/android/namespace_test.go
index 8bec0ad..9a791a5 100644
--- a/android/namespace_test.go
+++ b/android/namespace_test.go
@@ -582,6 +582,25 @@
 	}
 }
 
+// so that the generated .ninja file will have consistent names
+func TestRename(t *testing.T) {
+	_ = setupTest(t,
+		map[string]string{
+			"dir1": `
+			soong_namespace {
+			}
+			test_module {
+				name: "a",
+				deps: ["c"],
+			}
+			test_module {
+				name: "b",
+				rename: "c",
+			}
+		`})
+	// setupTest will report any errors
+}
+
 // some utils to support the tests
 
 func mockFiles(bps map[string]string) (files map[string][]byte) {
@@ -607,6 +626,9 @@
 	ctx.RegisterModuleType("test_module", ModuleFactoryAdaptor(newTestModule))
 	ctx.RegisterModuleType("soong_namespace", ModuleFactoryAdaptor(NamespaceFactory))
 	ctx.PreArchMutators(RegisterNamespaceMutator)
+	ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
+		ctx.BottomUp("rename", renameMutator)
+	})
 	ctx.Register()
 
 	_, errs = ctx.ParseBlueprintsFiles("Android.bp")
@@ -672,12 +694,16 @@
 type testModule struct {
 	ModuleBase
 	properties struct {
-		Deps []string
-		Id   string
+		Rename string
+		Deps   []string
+		Id     string
 	}
 }
 
 func (m *testModule) DepsMutator(ctx BottomUpMutatorContext) {
+	if m.properties.Rename != "" {
+		ctx.Rename(m.properties.Rename)
+	}
 	for _, d := range m.properties.Deps {
 		ctx.AddDependency(ctx.Module(), nil, d)
 	}
@@ -686,6 +712,14 @@
 func (m *testModule) GenerateAndroidBuildActions(ModuleContext) {
 }
 
+func renameMutator(ctx BottomUpMutatorContext) {
+	if m, ok := ctx.Module().(*testModule); ok {
+		if m.properties.Rename != "" {
+			ctx.Rename(m.properties.Rename)
+		}
+	}
+}
+
 func newTestModule() Module {
 	m := &testModule{}
 	m.AddProperties(&m.properties)
diff --git a/android/variable.go b/android/variable.go
index ef7d37b..3eee988 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -176,6 +176,8 @@
 	OdmPath     *string `json:",omitempty"`
 	ProductPath *string `json:",omitempty"`
 
+	UseClangLld *bool `json:",omitempty"`
+
 	ClangTidy  *bool   `json:",omitempty"`
 	TidyChecks *string `json:",omitempty"`
 
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index a578bcf..37877c8 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -64,6 +64,9 @@
 	"LOCAL_MODULE_SUFFIX":           skip, // TODO
 	"LOCAL_PATH":                    skip, // Nothing to do, except maybe avoid the "./" in paths?
 	"LOCAL_PRELINK_MODULE":          skip, // Already phased out
+	"LOCAL_BUILT_MODULE_STEM":       skip,
+	"LOCAL_USE_AAPT2":               skip, // Always enabled in Soong
+	"LOCAL_JAR_EXCLUDE_FILES":       skip, // Soong never excludes files from jars
 }
 
 // adds a group of properties all having the same type
@@ -94,6 +97,7 @@
 			"LOCAL_NOTICE_FILE":             "notice",
 			"LOCAL_JAVA_LANGUAGE_VERSION":   "java_version",
 			"LOCAL_INSTRUMENTATION_FOR":     "instrumentation_for",
+			"LOCAL_MANIFEST_FILE":           "manifest",
 
 			"LOCAL_DEX_PREOPT_PROFILE_CLASS_LISTING": "dex_preopt.profile",
 		})
@@ -129,6 +133,7 @@
 			"LOCAL_RENDERSCRIPT_FLAGS":    "renderscript.flags",
 
 			"LOCAL_JAVA_RESOURCE_DIRS":    "java_resource_dirs",
+			"LOCAL_RESOURCE_DIR":          "resource_dirs",
 			"LOCAL_JAVACFLAGS":            "javacflags",
 			"LOCAL_ERROR_PRONE_FLAGS":     "errorprone.javacflags",
 			"LOCAL_DX_FLAGS":              "dxflags",
@@ -143,7 +148,13 @@
 
 			"LOCAL_PROGUARD_FLAGS":      "optimize.proguard_flags",
 			"LOCAL_PROGUARD_FLAG_FILES": "optimize.proguard_flag_files",
+
+			// These will be rewritten to libs/static_libs by bpfix, after their presence is used to convert
+			// java_library_static to android_library.
+			"LOCAL_SHARED_ANDROID_LIBRARIES": "android_libs",
+			"LOCAL_STATIC_ANDROID_LIBRARIES": "android_static_libs",
 		})
+
 	addStandardProperties(bpparser.BoolType,
 		map[string]string{
 			// Bool properties
@@ -157,6 +168,7 @@
 			"LOCAL_NO_STANDARD_LIBRARIES":    "no_standard_libs",
 			"LOCAL_PACK_MODULE_RELOCATIONS":  "pack_relocations",
 			"LOCAL_TIDY":                     "tidy",
+			"LOCAL_USE_CLANG_LLD":            "use_clang_lld",
 			"LOCAL_PROPRIETARY_MODULE":       "proprietary",
 			"LOCAL_VENDOR_MODULE":            "vendor",
 			"LOCAL_ODM_MODULE":               "device_specific",
diff --git a/androidmk/cmd/androidmk/androidmk.go b/androidmk/cmd/androidmk/androidmk.go
index 6e0b474..b6a973c 100644
--- a/androidmk/cmd/androidmk/androidmk.go
+++ b/androidmk/cmd/androidmk/androidmk.go
@@ -239,7 +239,8 @@
 	}
 
 	// check for common supported but undesirable structures and clean them up
-	err := bpfix.FixTree(tree, bpfix.NewFixRequest().AddAll())
+	fixer := bpfix.NewFixer(tree)
+	tree, err := fixer.Fix(bpfix.NewFixRequest().AddAll())
 	if err != nil {
 		return "", []error{err}
 	}
diff --git a/androidmk/cmd/androidmk/androidmk_test.go b/androidmk/cmd/androidmk/androidmk_test.go
index 45df1a5..edf3d42 100644
--- a/androidmk/cmd/androidmk/androidmk_test.go
+++ b/androidmk/cmd/androidmk/androidmk_test.go
@@ -17,11 +17,10 @@
 import (
 	"bytes"
 	"fmt"
-	"os"
 	"strings"
 	"testing"
 
-	bpparser "github.com/google/blueprint/parser"
+	"android/soong/bpfix/bpfix"
 )
 
 var testCases = []struct {
@@ -498,6 +497,7 @@
 			include $(CLEAR_VARS)
 			LOCAL_SRC_FILES := test.jar
 			LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+			LOCAL_STATIC_ANDROID_LIBRARIES :=
 			include $(BUILD_PREBUILT)
 		`,
 		expected: `
@@ -522,28 +522,68 @@
 			}
 		`,
 	},
-}
 
-func reformatBlueprint(input string) string {
-	file, errs := bpparser.Parse("<testcase>", bytes.NewBufferString(input), bpparser.NewScope(nil))
-	if len(errs) > 0 {
-		for _, err := range errs {
-			fmt.Fprintln(os.Stderr, err)
-		}
-		panic(fmt.Sprintf("%d parsing errors in testcase:\n%s", len(errs), input))
-	}
+	{
+		desc: "aar",
+		in: `
+			include $(CLEAR_VARS)
+			LOCAL_SRC_FILES := test.java
+			LOCAL_RESOURCE_DIR := res
+			include $(BUILD_STATIC_JAVA_LIBRARY)
 
-	res, err := bpparser.Print(file)
-	if err != nil {
-		panic(fmt.Sprintf("Error printing testcase: %q", err))
-	}
+			include $(CLEAR_VARS)
+			LOCAL_SRC_FILES := test.java
+			LOCAL_STATIC_LIBRARIES := foo
+			LOCAL_STATIC_ANDROID_LIBRARIES := bar
+			include $(BUILD_STATIC_JAVA_LIBRARY)
 
-	return string(res)
+			include $(CLEAR_VARS)
+			LOCAL_SRC_FILES := test.java
+			LOCAL_SHARED_LIBRARIES := foo
+			LOCAL_SHARED_ANDROID_LIBRARIES := bar
+			include $(BUILD_STATIC_JAVA_LIBRARY)
+
+			include $(CLEAR_VARS)
+			LOCAL_SRC_FILES := test.java
+			LOCAL_STATIC_ANDROID_LIBRARIES :=
+			include $(BUILD_STATIC_JAVA_LIBRARY)
+		`,
+		expected: `
+			android_library {
+				srcs: ["test.java"],
+				resource_dirs: ["res"],
+			}
+
+			android_library {
+				srcs: ["test.java"],
+				static_libs: [
+					"foo",
+					"bar",
+				],
+			}
+
+			android_library {
+				srcs: ["test.java"],
+				libs: [
+					"foo",
+					"bar",
+				],
+			}
+
+			java_library_static {
+				srcs: ["test.java"],
+				static_libs: [],
+			}
+		`,
+	},
 }
 
 func TestEndToEnd(t *testing.T) {
 	for i, test := range testCases {
-		expected := reformatBlueprint(test.expected)
+		expected, err := bpfix.Reformat(test.expected)
+		if err != nil {
+			t.Error(err)
+		}
 
 		got, errs := convertFile(fmt.Sprintf("<testcase %d>", i), bytes.NewBufferString(test.in))
 		if len(errs) > 0 {
diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go
index 2c3cc6c..e4d4e34 100644
--- a/bpfix/bpfix/bpfix.go
+++ b/bpfix/bpfix/bpfix.go
@@ -18,17 +18,36 @@
 
 import (
 	"bytes"
+	"errors"
 	"fmt"
+	"io"
 	"path/filepath"
 
 	"github.com/google/blueprint/parser"
 )
 
+// Reformat takes a blueprint file as a string and returns a formatted version
+func Reformat(input string) (string, error) {
+	tree, err := parse("<string>", bytes.NewBufferString(input))
+	if err != nil {
+		return "", err
+	}
+
+	res, err := parser.Print(tree)
+	if err != nil {
+		return "", err
+	}
+
+	return string(res), nil
+}
+
 // A FixRequest specifies the details of which fixes to apply to an individual file
 // A FixRequest doesn't specify whether to do a dry run or where to write the results; that's in cmd/bpfix.go
 type FixRequest struct {
-	simplifyKnownRedundantVariables    bool
-	rewriteIncorrectAndroidmkPrebuilts bool
+	simplifyKnownRedundantVariables           bool
+	rewriteIncorrectAndroidmkPrebuilts        bool
+	rewriteIncorrectAndroidmkAndroidLibraries bool
+	mergeMatchingModuleProperties             bool
 }
 
 func NewFixRequest() FixRequest {
@@ -39,24 +58,39 @@
 	result = r
 	result.simplifyKnownRedundantVariables = true
 	result.rewriteIncorrectAndroidmkPrebuilts = true
+	result.rewriteIncorrectAndroidmkAndroidLibraries = true
+	result.mergeMatchingModuleProperties = true
 	return result
 }
 
-// FixTree repeatedly applies the fixes listed in the given FixRequest to the given File
+type Fixer struct {
+	tree *parser.File
+}
+
+func NewFixer(tree *parser.File) *Fixer {
+	fixer := &Fixer{tree}
+
+	// make a copy of the tree
+	fixer.reparse()
+
+	return fixer
+}
+
+// Fix repeatedly applies the fixes listed in the given FixRequest to the given File
 // until there is no fix that affects the tree
-func FixTree(tree *parser.File, config FixRequest) error {
-	prevIdentifier, err := fingerprint(tree)
+func (f *Fixer) Fix(config FixRequest) (*parser.File, error) {
+	prevIdentifier, err := f.fingerprint()
 	if err != nil {
-		return err
+		return nil, err
 	}
 
 	maxNumIterations := 20
 	i := 0
 	for {
-		err = fixTreeOnce(tree, config)
-		newIdentifier, err := fingerprint(tree)
+		err = f.fixTreeOnce(config)
+		newIdentifier, err := f.fingerprint()
 		if err != nil {
-			return err
+			return nil, err
 		}
 		if bytes.Equal(newIdentifier, prevIdentifier) {
 			break
@@ -67,31 +101,70 @@
 		// detect infinite loop
 		i++
 		if i >= maxNumIterations {
-			return fmt.Errorf("Applied fixes %d times and yet the tree continued to change. Is there an infinite loop?", i)
+			return nil, fmt.Errorf("Applied fixes %d times and yet the tree continued to change. Is there an infinite loop?", i)
 			break
 		}
 	}
-	return err
+	return f.tree, err
 }
 
 // returns a unique identifier for the given tree that can be used to determine whether the tree changed
-func fingerprint(tree *parser.File) (fingerprint []byte, err error) {
-	bytes, err := parser.Print(tree)
+func (f *Fixer) fingerprint() (fingerprint []byte, err error) {
+	bytes, err := parser.Print(f.tree)
 	if err != nil {
 		return nil, err
 	}
 	return bytes, nil
 }
 
-func fixTreeOnce(tree *parser.File, config FixRequest) error {
+func (f *Fixer) reparse() ([]byte, error) {
+	buf, err := parser.Print(f.tree)
+	if err != nil {
+		return nil, err
+	}
+	newTree, err := parse(f.tree.Name, bytes.NewReader(buf))
+	if err != nil {
+		return nil, err
+	}
+	f.tree = newTree
+	return buf, nil
+}
+
+func parse(name string, r io.Reader) (*parser.File, error) {
+	tree, errs := parser.Parse(name, r, parser.NewScope(nil))
+	if errs != nil {
+		s := "parse error: "
+		for _, err := range errs {
+			s += "\n" + err.Error()
+		}
+		return nil, errors.New(s)
+	}
+	return tree, nil
+}
+
+func (f *Fixer) fixTreeOnce(config FixRequest) error {
 	if config.simplifyKnownRedundantVariables {
-		err := simplifyKnownPropertiesDuplicatingEachOther(tree)
+		err := f.simplifyKnownPropertiesDuplicatingEachOther()
 		if err != nil {
 			return err
 		}
 	}
 	if config.rewriteIncorrectAndroidmkPrebuilts {
-		err := rewriteIncorrectAndroidmkPrebuilts(tree)
+		err := f.rewriteIncorrectAndroidmkPrebuilts()
+		if err != nil {
+			return err
+		}
+	}
+
+	if config.rewriteIncorrectAndroidmkAndroidLibraries {
+		err := f.rewriteIncorrectAndroidmkAndroidLibraries()
+		if err != nil {
+			return err
+		}
+	}
+
+	if config.mergeMatchingModuleProperties {
+		err := f.mergeMatchingModuleProperties()
 		if err != nil {
 			return err
 		}
@@ -99,13 +172,13 @@
 	return nil
 }
 
-func simplifyKnownPropertiesDuplicatingEachOther(tree *parser.File) error {
+func (f *Fixer) simplifyKnownPropertiesDuplicatingEachOther() error {
 	// remove from local_include_dirs anything in export_include_dirs
-	return removeMatchingModuleListProperties(tree, "export_include_dirs", "local_include_dirs")
+	return f.removeMatchingModuleListProperties("export_include_dirs", "local_include_dirs")
 }
 
-func rewriteIncorrectAndroidmkPrebuilts(tree *parser.File) error {
-	for _, def := range tree.Defs {
+func (f *Fixer) rewriteIncorrectAndroidmkPrebuilts() error {
+	for _, def := range f.tree.Defs {
 		mod, ok := def.(*parser.Module)
 		if !ok {
 			continue
@@ -127,6 +200,7 @@
 		switch filepath.Ext(src.Value) {
 		case ".jar":
 			renameProperty(mod, "srcs", "jars")
+
 		case ".aar":
 			renameProperty(mod, "srcs", "aars")
 			mod.Type = "android_library_import"
@@ -139,6 +213,146 @@
 	return nil
 }
 
+func (f *Fixer) rewriteIncorrectAndroidmkAndroidLibraries() error {
+	for _, def := range f.tree.Defs {
+		mod, ok := def.(*parser.Module)
+		if !ok {
+			continue
+		}
+
+		hasAndroidLibraries := hasNonEmptyLiteralListProperty(mod, "android_libs")
+		hasStaticAndroidLibraries := hasNonEmptyLiteralListProperty(mod, "android_static_libs")
+		hasResourceDirs := hasNonEmptyLiteralListProperty(mod, "resource_dirs")
+
+		if hasAndroidLibraries || hasStaticAndroidLibraries || hasResourceDirs {
+			if mod.Type == "java_library_static" {
+				mod.Type = "android_library"
+			}
+		}
+
+		if mod.Type == "java_import" && !hasStaticAndroidLibraries {
+			removeProperty(mod, "android_static_libs")
+		}
+
+		// These may conflict with existing libs and static_libs properties, but the
+		// mergeMatchingModuleProperties pass will fix it.
+		renameProperty(mod, "shared_libs", "libs")
+		renameProperty(mod, "android_libs", "libs")
+		renameProperty(mod, "android_static_libs", "static_libs")
+	}
+
+	return nil
+}
+
+func (f *Fixer) mergeMatchingModuleProperties() error {
+	// Make sure all the offsets are accurate
+	buf, err := f.reparse()
+	if err != nil {
+		return err
+	}
+
+	var patchlist parser.PatchList
+	for _, def := range f.tree.Defs {
+		mod, ok := def.(*parser.Module)
+		if !ok {
+			continue
+		}
+
+		err := mergeMatchingProperties(&mod.Properties, buf, &patchlist)
+		if err != nil {
+			return err
+		}
+	}
+
+	newBuf := new(bytes.Buffer)
+	err = patchlist.Apply(bytes.NewReader(buf), newBuf)
+	if err != nil {
+		return err
+	}
+
+	newTree, err := parse(f.tree.Name, newBuf)
+	if err != nil {
+		return err
+	}
+
+	f.tree = newTree
+
+	return nil
+}
+
+func mergeMatchingProperties(properties *[]*parser.Property, buf []byte, patchlist *parser.PatchList) error {
+	seen := make(map[string]*parser.Property)
+	for i := 0; i < len(*properties); i++ {
+		property := (*properties)[i]
+		if prev, exists := seen[property.Name]; exists {
+			err := mergeProperties(prev, property, buf, patchlist)
+			if err != nil {
+				return err
+			}
+			*properties = append((*properties)[:i], (*properties)[i+1:]...)
+		} else {
+			seen[property.Name] = property
+			if mapProperty, ok := property.Value.(*parser.Map); ok {
+				err := mergeMatchingProperties(&mapProperty.Properties, buf, patchlist)
+				if err != nil {
+					return err
+				}
+			}
+		}
+	}
+	return nil
+}
+
+func mergeProperties(a, b *parser.Property, buf []byte, patchlist *parser.PatchList) error {
+	if a.Value.Type() != b.Value.Type() {
+		return fmt.Errorf("type mismatch when merging properties %q: %s and %s", a.Name, a.Value.Type(), b.Value.Type())
+	}
+
+	switch a.Value.Type() {
+	case parser.StringType:
+		return fmt.Errorf("conflicting definitions of string property %q", a.Name)
+	case parser.ListType:
+		return mergeListProperties(a, b, buf, patchlist)
+	}
+
+	return nil
+}
+
+func mergeListProperties(a, b *parser.Property, buf []byte, patchlist *parser.PatchList) error {
+	aval, oka := a.Value.(*parser.List)
+	bval, okb := b.Value.(*parser.List)
+	if !oka || !okb {
+		// Merging expressions not supported yet
+		return nil
+	}
+
+	s := string(buf[bval.LBracePos.Offset+1 : bval.RBracePos.Offset])
+	if bval.LBracePos.Line != bval.RBracePos.Line {
+		if s[0] != '\n' {
+			panic("expected \n")
+		}
+		// If B is a multi line list, skip the first "\n" in case A already has a trailing "\n"
+		s = s[1:]
+	}
+	if aval.LBracePos.Line == aval.RBracePos.Line {
+		// A is a single line list with no trailing comma
+		if len(aval.Values) > 0 {
+			s = "," + s
+		}
+	}
+
+	err := patchlist.Add(aval.RBracePos.Offset, aval.RBracePos.Offset, s)
+	if err != nil {
+		return err
+	}
+	err = patchlist.Add(b.NamePos.Offset, b.End().Offset+2, "")
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
 // removes from <items> every item present in <removals>
 func filterExpressionList(items *parser.List, removals *parser.List) {
 	writeIndex := 0
@@ -163,8 +377,8 @@
 }
 
 // Remove each modules[i].Properties[<legacyName>][j] that matches a modules[i].Properties[<canonicalName>][k]
-func removeMatchingModuleListProperties(tree *parser.File, canonicalName string, legacyName string) error {
-	for _, def := range tree.Defs {
+func (f *Fixer) removeMatchingModuleListProperties(canonicalName string, legacyName string) error {
+	for _, def := range f.tree.Defs {
 		mod, ok := def.(*parser.Module)
 		if !ok {
 			continue
@@ -182,6 +396,11 @@
 	return nil
 }
 
+func hasNonEmptyLiteralListProperty(mod *parser.Module, name string) bool {
+	list, found := getLiteralListProperty(mod, name)
+	return found && len(list.Values) > 0
+}
+
 func getLiteralListProperty(mod *parser.Module, name string) (list *parser.List, found bool) {
 	prop, ok := mod.GetProperty(name)
 	if !ok {
diff --git a/bpfix/bpfix/bpfix_test.go b/bpfix/bpfix/bpfix_test.go
index e17e815..51708eb 100644
--- a/bpfix/bpfix/bpfix_test.go
+++ b/bpfix/bpfix/bpfix_test.go
@@ -17,6 +17,7 @@
 package bpfix
 
 import (
+	"bytes"
 	"fmt"
 	"strings"
 	"testing"
@@ -62,14 +63,16 @@
 		t.Fatalf("%d parse errors", len(errs))
 	}
 
+	fixer := NewFixer(tree)
+
 	// apply simplifications
-	err := simplifyKnownPropertiesDuplicatingEachOther(tree)
+	err := fixer.simplifyKnownPropertiesDuplicatingEachOther()
 	if len(errs) > 0 {
 		t.Fatal(err)
 	}
 
 	// lookup legacy property
-	mod := tree.Defs[0].(*parser.Module)
+	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")
@@ -113,3 +116,130 @@
 	implFilterListTest(t, []string{}, []string{"include"}, []string{})
 	implFilterListTest(t, []string{}, []string{}, []string{})
 }
+
+func TestMergeMatchingProperties(t *testing.T) {
+	tests := []struct {
+		name string
+		in   string
+		out  string
+	}{
+		{
+			name: "empty",
+			in: `
+				java_library {
+					name: "foo",
+					static_libs: [],
+					static_libs: [],
+				}
+			`,
+			out: `
+				java_library {
+					name: "foo",
+					static_libs: [],
+				}
+			`,
+		},
+		{
+			name: "single line into multiline",
+			in: `
+				java_library {
+					name: "foo",
+					static_libs: [
+						"a",
+						"b",
+					],
+					//c1
+					static_libs: ["c" /*c2*/],
+				}
+			`,
+			out: `
+				java_library {
+					name: "foo",
+					static_libs: [
+						"a",
+						"b",
+						"c", /*c2*/
+					],
+					//c1
+				}
+			`,
+		},
+		{
+			name: "multiline into multiline",
+			in: `
+				java_library {
+					name: "foo",
+					static_libs: [
+						"a",
+						"b",
+					],
+					//c1
+					static_libs: [
+						//c2
+						"c", //c3
+						"d",
+					],
+				}
+			`,
+			out: `
+				java_library {
+					name: "foo",
+					static_libs: [
+						"a",
+						"b",
+						//c2
+						"c", //c3
+						"d",
+					],
+					//c1
+				}
+			`,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			expected, err := Reformat(test.out)
+			if err != nil {
+				t.Error(err)
+			}
+
+			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)
+				}
+
+				out, err := parser.Print(fixer.tree)
+				if err != nil {
+					t.Fatal(err)
+				}
+
+				prev = got
+				got = string(out)
+				passes++
+			}
+
+			if got != expected {
+				t.Errorf("failed testcase '%s'\ninput:\n%s\n\nexpected:\n%s\ngot:\n%s\n",
+					test.name, in, expected, got)
+			}
+
+		})
+	}
+}
diff --git a/bpfix/cmd/bpfix.go b/bpfix/cmd/bpfix.go
index 461f41d..2fde383 100644
--- a/bpfix/cmd/bpfix.go
+++ b/bpfix/cmd/bpfix.go
@@ -75,7 +75,8 @@
 	}
 
 	// compute and apply any requested fixes
-	err = bpfix.FixTree(file, fixRequest)
+	fixer := bpfix.NewFixer(file)
+	file, err = fixer.Fix(fixRequest)
 	if err != nil {
 		return err
 	}
diff --git a/cc/cc.go b/cc/cc.go
index 9c86828..8c11429 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1115,17 +1115,11 @@
 	toStl := to.stl.Properties.SelectedStl
 	if fromStl == "" || toStl == "" {
 		// Libraries that don't use the STL are unrestricted.
-		return
-	}
-
-	if fromStl == "ndk_system" || toStl == "ndk_system" {
+	} else if fromStl == "ndk_system" || toStl == "ndk_system" {
 		// We can be permissive with the system "STL" since it is only the C++
 		// ABI layer, but in the future we should make sure that everyone is
 		// using either libc++ or nothing.
-		return
-	}
-
-	if getNdkStlFamily(ctx, from) != getNdkStlFamily(ctx, to) {
+	} else if getNdkStlFamily(ctx, from) != getNdkStlFamily(ctx, to) {
 		ctx.ModuleErrorf("uses %q and depends on %q which uses incompatible %q",
 			from.stl.Properties.SelectedStl, ctx.OtherModuleName(to),
 			to.stl.Properties.SelectedStl)
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index 5bb7749..74c936f 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -35,6 +35,9 @@
 		"-Wl,--icf=safe",
 	}
 
+	arm64Lldflags = append(ClangFilterUnknownLldflags(arm64Ldflags),
+		"-Wl,-z,max-page-size=4096")
+
 	arm64Cppflags = []string{}
 
 	arm64CpuVariantCflags = map[string][]string{
@@ -81,11 +84,13 @@
 
 	pctx.StaticVariable("Arm64Cflags", strings.Join(arm64Cflags, " "))
 	pctx.StaticVariable("Arm64Ldflags", strings.Join(arm64Ldflags, " "))
+	pctx.StaticVariable("Arm64Lldflags", strings.Join(arm64Lldflags, " "))
 	pctx.StaticVariable("Arm64Cppflags", strings.Join(arm64Cppflags, " "))
 	pctx.StaticVariable("Arm64IncludeFlags", bionicHeaders("arm64"))
 
 	pctx.StaticVariable("Arm64ClangCflags", strings.Join(ClangFilterUnknownCflags(arm64Cflags), " "))
 	pctx.StaticVariable("Arm64ClangLdflags", strings.Join(ClangFilterUnknownCflags(arm64Ldflags), " "))
+	pctx.StaticVariable("Arm64ClangLldflags", strings.Join(ClangFilterUnknownCflags(arm64Lldflags), " "))
 	pctx.StaticVariable("Arm64ClangCppflags", strings.Join(ClangFilterUnknownCflags(arm64Cppflags), " "))
 
 	pctx.StaticVariable("Arm64CortexA53Cflags",
@@ -188,6 +193,10 @@
 	return "${config.Arm64Ldflags}"
 }
 
+func (t *toolchainArm64) ClangLldflags() string {
+	return "${config.Arm64Lldflags}"
+}
+
 func (t *toolchainArm64) ToolchainClangCflags() string {
 	return t.toolchainClangCflags
 }
diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go
index 66b3b38..02bd9eb 100644
--- a/cc/config/arm_device.go
+++ b/cc/config/arm_device.go
@@ -39,6 +39,8 @@
 		"-Wl,-m,armelf",
 	}
 
+	armLldflags = ClangFilterUnknownLldflags(armLdflags)
+
 	armArmCflags = []string{
 		"-fstrict-aliasing",
 	}
@@ -169,6 +171,7 @@
 	pctx.StaticVariable("ArmToolchainCflags", strings.Join(armToolchainCflags, " "))
 	pctx.StaticVariable("ArmCflags", strings.Join(armCflags, " "))
 	pctx.StaticVariable("ArmLdflags", strings.Join(armLdflags, " "))
+	pctx.StaticVariable("ArmLldflags", strings.Join(armLldflags, " "))
 	pctx.StaticVariable("ArmCppflags", strings.Join(armCppflags, " "))
 	pctx.StaticVariable("ArmIncludeFlags", bionicHeaders("arm"))
 
@@ -196,6 +199,7 @@
 	pctx.StaticVariable("ArmToolchainClangCflags", strings.Join(ClangFilterUnknownCflags(armToolchainCflags), " "))
 	pctx.StaticVariable("ArmClangCflags", strings.Join(ClangFilterUnknownCflags(armCflags), " "))
 	pctx.StaticVariable("ArmClangLdflags", strings.Join(ClangFilterUnknownCflags(armLdflags), " "))
+	pctx.StaticVariable("ArmClangLldflags", strings.Join(ClangFilterUnknownCflags(armLldflags), " "))
 	pctx.StaticVariable("ArmClangCppflags", strings.Join(ClangFilterUnknownCflags(armCppflags), " "))
 
 	// Clang ARM vs. Thumb instruction set cflags
@@ -274,6 +278,7 @@
 type toolchainArm struct {
 	toolchain32Bit
 	ldflags                               string
+	lldflags                              string
 	toolchainCflags, toolchainClangCflags string
 }
 
@@ -350,6 +355,10 @@
 	return t.ldflags
 }
 
+func (t *toolchainArm) ClangLldflags() string {
+	return t.lldflags // TODO: handle V8 cases
+}
+
 func (t *toolchainArm) ClangInstructionSetFlags(isa string) (string, error) {
 	switch isa {
 	case "arm":
@@ -403,6 +412,7 @@
 			"${config.ArmLdflags}",
 			fixCortexA8,
 		}, " "),
+		lldflags:             "${config.ArmLldflags}",
 		toolchainClangCflags: strings.Join(toolchainClangCflags, " "),
 	}
 }
diff --git a/cc/config/clang.go b/cc/config/clang.go
index 46d6fe2..1323849 100644
--- a/cc/config/clang.go
+++ b/cc/config/clang.go
@@ -83,6 +83,15 @@
 	"--enable-stdcall-fixup",
 })
 
+// Ldflags that should be filtered out when linking with clang lld
+var ClangUnknownLldflags = sorted([]string{
+	"-fuse-ld=gold",
+	"-Wl,--icf=safe",
+	"-Wl,--fix-cortex-a8",
+	"-Wl,--no-fix-cortex-a8",
+	"-Wl,-m,aarch64_elf64_le_vec",
+})
+
 var ClangLibToolingUnknownCflags = []string{
 	"-flto*",
 	"-fsanitize*",
@@ -182,6 +191,17 @@
 	return ret
 }
 
+func ClangFilterUnknownLldflags(lldflags []string) []string {
+	ret := make([]string, 0, len(lldflags))
+	for _, f := range lldflags {
+		if !inListSorted(f, ClangUnknownLldflags) {
+			ret = append(ret, f)
+		}
+	}
+
+	return ret
+}
+
 func inListSorted(s string, list []string) bool {
 	for _, l := range list {
 		if s == l {
diff --git a/cc/config/global.go b/cc/config/global.go
index 989c7ee..051eba5 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -87,12 +87,20 @@
 		"-Wl,--no-undefined-version",
 	}
 
+	deviceGlobalLldflags = append(ClangFilterUnknownLldflags(deviceGlobalLdflags),
+		[]string{
+			"-Wl,--pack-dyn-relocs=android",
+			"-fuse-ld=lld",
+		}...)
+
 	hostGlobalCflags = []string{}
 
 	hostGlobalCppflags = []string{}
 
 	hostGlobalLdflags = []string{}
 
+	hostGlobalLldflags = []string{}
+
 	commonGlobalCppflags = []string{
 		"-Wsign-promo",
 	}
@@ -141,9 +149,11 @@
 	pctx.StaticVariable("DeviceGlobalCflags", strings.Join(deviceGlobalCflags, " "))
 	pctx.StaticVariable("DeviceGlobalCppflags", strings.Join(deviceGlobalCppflags, " "))
 	pctx.StaticVariable("DeviceGlobalLdflags", strings.Join(deviceGlobalLdflags, " "))
+	pctx.StaticVariable("DeviceGlobalLldflags", strings.Join(deviceGlobalLldflags, " "))
 	pctx.StaticVariable("HostGlobalCflags", strings.Join(hostGlobalCflags, " "))
 	pctx.StaticVariable("HostGlobalCppflags", strings.Join(hostGlobalCppflags, " "))
 	pctx.StaticVariable("HostGlobalLdflags", strings.Join(hostGlobalLdflags, " "))
+	pctx.StaticVariable("HostGlobalLldflags", strings.Join(hostGlobalLldflags, " "))
 	pctx.StaticVariable("NoOverrideGlobalCflags", strings.Join(noOverrideGlobalCflags, " "))
 
 	pctx.StaticVariable("CommonGlobalCppflags", strings.Join(commonGlobalCppflags, " "))
diff --git a/cc/config/mips64_device.go b/cc/config/mips64_device.go
index a6191b6..6fa2571 100644
--- a/cc/config/mips64_device.go
+++ b/cc/config/mips64_device.go
@@ -155,6 +155,11 @@
 	return "${config.Mips64ClangLdflags}"
 }
 
+func (t *toolchainMips64) ClangLldflags() string {
+	// TODO: define and use Mips64ClangLldflags
+	return "${config.Mips64ClangLdflags}"
+}
+
 func (toolchainMips64) SanitizerRuntimeLibraryArch() string {
 	return "mips64"
 }
diff --git a/cc/config/mips_device.go b/cc/config/mips_device.go
index 9709ada..b815fc6 100644
--- a/cc/config/mips_device.go
+++ b/cc/config/mips_device.go
@@ -205,6 +205,11 @@
 	return "${config.MipsClangLdflags}"
 }
 
+func (t *toolchainMips) ClangLldflags() string {
+	// TODO: define and use MipsClangLldflags
+	return "${config.MipsClangLdflags}"
+}
+
 func (toolchainMips) SanitizerRuntimeLibraryArch() string {
 	return "mips"
 }
diff --git a/cc/config/toolchain.go b/cc/config/toolchain.go
index 7961575..ca863a7 100644
--- a/cc/config/toolchain.go
+++ b/cc/config/toolchain.go
@@ -66,6 +66,7 @@
 	ClangCflags() string
 	ClangCppflags() string
 	ClangLdflags() string
+	ClangLldflags() string
 	ClangInstructionSetFlags(string) (string, error)
 
 	ndkTriple() string
diff --git a/cc/config/x86_64_device.go b/cc/config/x86_64_device.go
index 12f3e6f..ba03094 100644
--- a/cc/config/x86_64_device.go
+++ b/cc/config/x86_64_device.go
@@ -32,6 +32,8 @@
 		"-Wl,--hash-style=gnu",
 	}
 
+	x86_64Lldflags = ClangFilterUnknownLldflags(x86_64Ldflags)
+
 	x86_64ArchVariantCflags = map[string][]string{
 		"": []string{
 			"-march=x86-64",
@@ -125,12 +127,14 @@
 
 	pctx.StaticVariable("X86_64Cflags", strings.Join(x86_64Cflags, " "))
 	pctx.StaticVariable("X86_64Ldflags", strings.Join(x86_64Ldflags, " "))
+	pctx.StaticVariable("X86_64Lldflags", strings.Join(x86_64Lldflags, " "))
 	pctx.StaticVariable("X86_64Cppflags", strings.Join(x86_64Cppflags, " "))
 	pctx.StaticVariable("X86_64IncludeFlags", bionicHeaders("x86"))
 
 	// Clang cflags
 	pctx.StaticVariable("X86_64ClangCflags", strings.Join(ClangFilterUnknownCflags(x86_64Cflags), " "))
 	pctx.StaticVariable("X86_64ClangLdflags", strings.Join(ClangFilterUnknownCflags(x86_64Ldflags), " "))
+	pctx.StaticVariable("X86_64ClangLldflags", strings.Join(ClangFilterUnknownCflags(x86_64Lldflags), " "))
 	pctx.StaticVariable("X86_64ClangCppflags", strings.Join(ClangFilterUnknownCflags(x86_64Cppflags), " "))
 
 	// Yasm flags
@@ -215,6 +219,10 @@
 	return "${config.X86_64Ldflags}"
 }
 
+func (t *toolchainX86_64) ClangLldflags() string {
+	return "${config.X86_64Lldflags}"
+}
+
 func (t *toolchainX86_64) YasmFlags() string {
 	return "${config.X86_64YasmFlags}"
 }
diff --git a/cc/config/x86_darwin_host.go b/cc/config/x86_darwin_host.go
index cae9757..4aa8242 100644
--- a/cc/config/x86_darwin_host.go
+++ b/cc/config/x86_darwin_host.go
@@ -273,10 +273,20 @@
 	return "${config.DarwinClangLdflags} ${config.DarwinX86ClangLdflags}"
 }
 
+func (t *toolchainDarwinX86) ClangLldflags() string {
+	// TODO: define and use Darwin*ClangLldflags
+	return "${config.DarwinClangLdflags} ${config.DarwinX86ClangLdflags}"
+}
+
 func (t *toolchainDarwinX8664) ClangLdflags() string {
 	return "${config.DarwinClangLdflags} ${config.DarwinX8664ClangLdflags}"
 }
 
+func (t *toolchainDarwinX8664) ClangLldflags() string {
+	// TODO: define and use Darwin*ClangLldflags
+	return "${config.DarwinClangLdflags} ${config.DarwinX8664ClangLdflags}"
+}
+
 func (t *toolchainDarwinX86) YasmFlags() string {
 	return "${config.DarwinX86YasmFlags}"
 }
diff --git a/cc/config/x86_device.go b/cc/config/x86_device.go
index b9ce4af..15188cf 100644
--- a/cc/config/x86_device.go
+++ b/cc/config/x86_device.go
@@ -38,6 +38,8 @@
 		"-Wl,--hash-style=gnu",
 	}
 
+	x86Lldflags = ClangFilterUnknownLldflags(x86Ldflags)
+
 	x86ArchVariantCflags = map[string][]string{
 		"": []string{
 			"-march=prescott",
@@ -149,12 +151,14 @@
 
 	pctx.StaticVariable("X86Cflags", strings.Join(x86Cflags, " "))
 	pctx.StaticVariable("X86Ldflags", strings.Join(x86Ldflags, " "))
+	pctx.StaticVariable("X86Lldflags", strings.Join(x86Lldflags, " "))
 	pctx.StaticVariable("X86Cppflags", strings.Join(x86Cppflags, " "))
 	pctx.StaticVariable("X86IncludeFlags", bionicHeaders("x86"))
 
 	// Clang cflags
 	pctx.StaticVariable("X86ClangCflags", strings.Join(ClangFilterUnknownCflags(x86ClangCflags), " "))
 	pctx.StaticVariable("X86ClangLdflags", strings.Join(ClangFilterUnknownCflags(x86Ldflags), " "))
+	pctx.StaticVariable("X86ClangLldflags", strings.Join(ClangFilterUnknownCflags(x86Lldflags), " "))
 	pctx.StaticVariable("X86ClangCppflags", strings.Join(ClangFilterUnknownCflags(x86Cppflags), " "))
 
 	// Yasm flags
@@ -239,6 +243,10 @@
 	return "${config.X86Ldflags}"
 }
 
+func (t *toolchainX86) ClangLldflags() string {
+	return "${config.X86Lldflags}"
+}
+
 func (t *toolchainX86) YasmFlags() string {
 	return "${config.X86YasmFlags}"
 }
diff --git a/cc/config/x86_linux_bionic_host.go b/cc/config/x86_linux_bionic_host.go
index 9f0bbbd..057e905 100644
--- a/cc/config/x86_linux_bionic_host.go
+++ b/cc/config/x86_linux_bionic_host.go
@@ -126,6 +126,11 @@
 	return "${config.LinuxBionicLdflags}"
 }
 
+func (t *toolchainLinuxBionic) ClangLldflags() string {
+	// TODO: define and use LinuxBionicLldflags
+	return "${config.LinuxBionicLdflags}"
+}
+
 func (t *toolchainLinuxBionic) ToolchainClangCflags() string {
 	return "-m64 -march=x86-64" +
 		// TODO: We're not really android, but we don't have a triple yet b/31393676
diff --git a/cc/config/x86_linux_host.go b/cc/config/x86_linux_host.go
index 4f05068..6144fc2 100644
--- a/cc/config/x86_linux_host.go
+++ b/cc/config/x86_linux_host.go
@@ -241,10 +241,20 @@
 	return "${config.LinuxClangLdflags} ${config.LinuxX86ClangLdflags}"
 }
 
+func (t *toolchainLinuxX86) ClangLldflags() string {
+	// TODO: define and use Linux*ClangLldflags
+	return "${config.LinuxClangLdflags} ${config.LinuxX86ClangLdflags}"
+}
+
 func (t *toolchainLinuxX8664) ClangLdflags() string {
 	return "${config.LinuxClangLdflags} ${config.LinuxX8664ClangLdflags}"
 }
 
+func (t *toolchainLinuxX8664) ClangLldflags() string {
+	// TODO: define and use Linux*ClangLldflags
+	return "${config.LinuxClangLdflags} ${config.LinuxX8664ClangLdflags}"
+}
+
 func (t *toolchainLinuxX86) YasmFlags() string {
 	return "${config.LinuxX86YasmFlags}"
 }
diff --git a/cc/config/x86_windows_host.go b/cc/config/x86_windows_host.go
index 016e711..fea6291 100644
--- a/cc/config/x86_windows_host.go
+++ b/cc/config/x86_windows_host.go
@@ -245,10 +245,20 @@
 	return "${config.WindowsClangLdflags} ${config.WindowsX86ClangLdflags}"
 }
 
+func (t *toolchainWindowsX86) ClangLldflags() string {
+	// TODO: define and use Windows*ClangLldflags
+	return "${config.WindowsClangLdflags} ${config.WindowsX86ClangLdflags}"
+}
+
 func (t *toolchainWindowsX8664) ClangLdflags() string {
 	return "${config.WindowsClangLdflags} ${config.WindowsX8664ClangLdflags}"
 }
 
+func (t *toolchainWindowsX8664) ClangLldflags() string {
+	// TODO: define and use Windows*ClangLldflags
+	return "${config.WindowsClangLdflags} ${config.WindowsX8664ClangLdflags}"
+}
+
 func (t *toolchainWindows) ShlibSuffix() string {
 	return ".dll"
 }
diff --git a/cc/linker.go b/cc/linker.go
index bcedc8d..2176306 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -58,6 +58,9 @@
 	// don't link in libgcc.a
 	No_libgcc *bool
 
+	// Use clang lld instead of gnu ld.
+	Use_clang_lld *bool
+
 	// -l arguments to pass to linker for host-provided shared libraries
 	Host_ldlibs []string `android:"arch_variant"`
 
@@ -201,6 +204,15 @@
 	return deps
 }
 
+func (linker *baseLinker) useClangLld(ctx ModuleContext) bool {
+	if linker.Properties.Use_clang_lld != nil {
+		return Bool(linker.Properties.Use_clang_lld)
+	}
+	return ctx.Config().UseClangLld()
+}
+
+// ModuleContext extends BaseModuleContext
+// BaseModuleContext should know if LLD is used?
 func (linker *baseLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags {
 	toolchain := ctx.toolchain()
 
@@ -209,7 +221,11 @@
 		hod = "Device"
 	}
 
-	flags.LdFlags = append(flags.LdFlags, fmt.Sprintf("${config.%sGlobalLdflags}", hod))
+	if flags.Clang && linker.useClangLld(ctx) {
+		flags.LdFlags = append(flags.LdFlags, fmt.Sprintf("${config.%sGlobalLldflags}", hod))
+	} else {
+		flags.LdFlags = append(flags.LdFlags, fmt.Sprintf("${config.%sGlobalLdflags}", hod))
+	}
 	if Bool(linker.Properties.Allow_undefined_symbols) {
 		if ctx.Darwin() {
 			// darwin defaults to treating undefined symbols as errors
@@ -219,7 +235,9 @@
 		flags.LdFlags = append(flags.LdFlags, "-Wl,--no-undefined")
 	}
 
-	if flags.Clang {
+	if flags.Clang && linker.useClangLld(ctx) {
+		flags.LdFlags = append(flags.LdFlags, toolchain.ClangLldflags())
+	} else if flags.Clang {
 		flags.LdFlags = append(flags.LdFlags, toolchain.ClangLdflags())
 	} else {
 		flags.LdFlags = append(flags.LdFlags, toolchain.Ldflags())
diff --git a/cc/lto.go b/cc/lto.go
index 85057cf..fd2a869 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -49,6 +49,9 @@
 	// since it is an object dependency of an LTO module.
 	FullDep bool `blueprint:"mutated"`
 	ThinDep bool `blueprint:"mutated"`
+
+	// Use clang lld instead of gnu ld.
+	Use_clang_lld *bool
 }
 
 type lto struct {
@@ -69,6 +72,13 @@
 	return deps
 }
 
+func (lto *lto) useClangLld(ctx BaseModuleContext) bool {
+	if lto.Properties.Use_clang_lld != nil {
+		return Bool(lto.Properties.Use_clang_lld)
+	}
+	return ctx.Config().UseClangLld()
+}
+
 func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags {
 	if lto.LTO() {
 		var ltoFlag string
@@ -82,7 +92,7 @@
 		flags.CFlags = append(flags.CFlags, ltoFlag)
 		flags.LdFlags = append(flags.LdFlags, ltoFlag)
 
-		if ctx.Config().IsEnvTrue("USE_THINLTO_CACHE") && Bool(lto.Properties.Lto.Thin) {
+		if ctx.Config().IsEnvTrue("USE_THINLTO_CACHE") && Bool(lto.Properties.Lto.Thin) && !lto.useClangLld(ctx) {
 			// Set appropriate ThinLTO cache policy
 			cacheDirFormat := "-Wl,-plugin-opt,cache-dir="
 			cacheDir := android.PathForOutput(ctx, "thinlto-cache").String()
@@ -99,7 +109,7 @@
 
 		// If the module does not have a profile, be conservative and do not inline
 		// or unroll loops during LTO, in order to prevent significant size bloat.
-		if !ctx.isPgoCompile() {
+		if !ctx.isPgoCompile() && !lto.useClangLld(ctx) {
 			flags.LdFlags = append(flags.LdFlags, "-Wl,-plugin-opt,-inline-threshold=0")
 			flags.LdFlags = append(flags.LdFlags, "-Wl,-plugin-opt,-unroll-threshold=0")
 		}
diff --git a/cc/makevars.go b/cc/makevars.go
index 83a662f..bb81dcb 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -232,6 +232,12 @@
 		toolchain.ToolchainLdflags(),
 		productExtraLdflags,
 	}, " "))
+	ctx.Strict(makePrefix+"GLOBAL_LLDFLAGS", strings.Join([]string{
+		fmt.Sprintf("${config.%sGlobalLldflags}", hod),
+		toolchain.Ldflags(),
+		toolchain.ToolchainLdflags(),
+		productExtraLdflags,
+	}, " "))
 
 	includeFlags, err := ctx.Eval(toolchain.IncludeFlags())
 	if err != nil {
@@ -280,6 +286,13 @@
 			productExtraLdflags,
 			clangExtras,
 		}, " "))
+		ctx.Strict(clangPrefix+"GLOBAL_LLDFLAGS", strings.Join([]string{
+			fmt.Sprintf("${config.%sGlobalLldflags}", hod),
+			toolchain.ClangLldflags(),
+			toolchain.ToolchainClangLdflags(),
+			productExtraLdflags,
+			clangExtras,
+		}, " "))
 
 		if target.Os.Class == android.Device {
 			ctx.Strict(secondPrefix+"ADDRESS_SANITIZER_RUNTIME_LIBRARY", strings.TrimSuffix(config.AddressSanitizerRuntimeLibrary(toolchain), ".so"))
diff --git a/cc/relocation_packer.go b/cc/relocation_packer.go
index 5006623..f6a1fe4 100644
--- a/cc/relocation_packer.go
+++ b/cc/relocation_packer.go
@@ -38,12 +38,22 @@
 	// This will be true even if we're embedded in Make, in which case
 	// we'll defer to make to actually do the packing.
 	PackingRelocations bool `blueprint:"mutated"`
+
+	// Use clang lld instead of gnu ld.
+	Use_clang_lld *bool
 }
 
 type relocationPacker struct {
 	Properties RelocationPackerProperties
 }
 
+func (p *relocationPacker) useClangLld(ctx BaseModuleContext) bool {
+	if p.Properties.Use_clang_lld != nil {
+		return Bool(p.Properties.Use_clang_lld)
+	}
+	return ctx.Config().UseClangLld()
+}
+
 func (p *relocationPacker) packingInit(ctx BaseModuleContext) {
 	enabled := true
 	// Relocation packer isn't available on Darwin yet
@@ -56,6 +66,11 @@
 	if ctx.Config().Getenv("DISABLE_RELOCATION_PACKER") == "true" {
 		enabled = false
 	}
+	// Relocation packer does not work with lld output files.
+	// Packed files won't load.
+	if p.useClangLld(ctx) {
+		enabled = false
+	}
 	if ctx.useSdk() {
 		enabled = false
 	}
diff --git a/java/aapt2.go b/java/aapt2.go
index fd7388e..61e9451 100644
--- a/java/aapt2.go
+++ b/java/aapt2.go
@@ -111,7 +111,8 @@
 
 var aapt2LinkRule = pctx.AndroidStaticRule("aapt2Link",
 	blueprint.RuleParams{
-		Command: `${config.Aapt2Cmd} link -o $out $flags --java $genDir --proguard $proguardOptions $inFlags && ` +
+		Command: `${config.Aapt2Cmd} link -o $out $flags --java $genDir --proguard $proguardOptions ` +
+			`--output-text-symbols ${rTxt} $inFlags && ` +
 			`${config.SoongZipCmd} -write_if_changed -jar -o $genJar -C $genDir -D $genDir`,
 		CommandDeps: []string{
 			"${config.Aapt2Cmd}",
@@ -119,7 +120,7 @@
 		},
 		Restat: true,
 	},
-	"flags", "inFlags", "proguardOptions", "genDir", "genJar")
+	"flags", "inFlags", "proguardOptions", "genDir", "genJar", "rTxt")
 
 var fileListToFileRule = pctx.AndroidStaticRule("fileListToFile",
 	blueprint.RuleParams{
@@ -129,7 +130,7 @@
 	})
 
 func aapt2Link(ctx android.ModuleContext,
-	packageRes, genJar, proguardOptions android.WritablePath,
+	packageRes, genJar, proguardOptions, rTxt android.WritablePath,
 	flags []string, deps android.Paths,
 	compiledRes, compiledOverlay android.Paths) {
 
@@ -171,13 +172,14 @@
 		Description:     "aapt2 link",
 		Implicits:       deps,
 		Output:          packageRes,
-		ImplicitOutputs: android.WritablePaths{proguardOptions, genJar},
+		ImplicitOutputs: android.WritablePaths{proguardOptions, genJar, rTxt},
 		Args: map[string]string{
 			"flags":           strings.Join(flags, " "),
 			"inFlags":         strings.Join(inFlags, " "),
 			"proguardOptions": proguardOptions.String(),
 			"genDir":          genDir.String(),
 			"genJar":          genJar.String(),
+			"rTxt":            rTxt.String(),
 		},
 	})
 }
diff --git a/java/aar.go b/java/aar.go
index 0df3632..57c752c 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -16,21 +16,307 @@
 
 import (
 	"android/soong/android"
+	"strings"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
 )
 
+type AndroidLibraryDependency interface {
+	Dependency
+	ExportPackage() android.Path
+}
+
+func init() {
+	android.RegisterModuleType("android_library_import", AARImportFactory)
+	android.RegisterModuleType("android_library", AndroidLibraryFactory)
+}
+
+//
+// AAR (android library)
+//
+
+type androidLibraryProperties struct {
+	BuildAAR bool `blueprint:"mutated"`
+}
+
+type aaptProperties struct {
+	// flags passed to aapt when creating the apk
+	Aaptflags []string
+
+	// list of directories relative to the Blueprints file containing assets.
+	// Defaults to "assets"
+	Asset_dirs []string
+
+	// list of directories relative to the Blueprints file containing
+	// Android resources
+	Resource_dirs []string
+
+	// path to AndroidManifest.xml.  If unset, defaults to "AndroidManifest.xml".
+	Manifest *string
+}
+
+type aapt struct {
+	aaptSrcJar          android.Path
+	exportPackage       android.Path
+	manifestPath        android.Path
+	proguardOptionsFile android.Path
+	rroDirs             android.Paths
+	rTxt                android.Path
+
+	aaptProperties aaptProperties
+}
+
+func (a *aapt) ExportPackage() android.Path {
+	return a.exportPackage
+}
+
+func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkVersion string) (flags []string, deps android.Paths,
+	resDirs, overlayDirs []globbedResourceDir, overlayFiles, rroDirs android.Paths, manifestPath android.Path) {
+
+	hasVersionCode := false
+	hasVersionName := false
+	hasProduct := false
+	for _, f := range a.aaptProperties.Aaptflags {
+		if strings.HasPrefix(f, "--version-code") {
+			hasVersionCode = true
+		} else if strings.HasPrefix(f, "--version-name") {
+			hasVersionName = true
+		} else if strings.HasPrefix(f, "--product") {
+			hasProduct = true
+		}
+	}
+
+	var linkFlags []string
+
+	// Flags specified in Android.bp
+	linkFlags = append(linkFlags, a.aaptProperties.Aaptflags...)
+
+	linkFlags = append(linkFlags, "--no-static-lib-packages")
+
+	// Find implicit or explicit asset and resource dirs
+	assetDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Asset_dirs, "assets")
+	resourceDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Resource_dirs, "res")
+
+	var linkDeps android.Paths
+
+	// Glob directories into lists of paths
+	for _, dir := range resourceDirs {
+		resDirs = append(resDirs, globbedResourceDir{
+			dir:   dir,
+			files: androidResourceGlob(ctx, dir),
+		})
+		resOverlayDirs, resRRODirs := overlayResourceGlob(ctx, dir)
+		overlayDirs = append(overlayDirs, resOverlayDirs...)
+		rroDirs = append(rroDirs, resRRODirs...)
+	}
+
+	var assetFiles android.Paths
+	for _, dir := range assetDirs {
+		assetFiles = append(assetFiles, androidResourceGlob(ctx, dir)...)
+	}
+
+	// App manifest file
+	manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
+	manifestPath = android.PathForModuleSrc(ctx, manifestFile)
+	linkFlags = append(linkFlags, "--manifest "+manifestPath.String())
+	linkDeps = append(linkDeps, manifestPath)
+
+	linkFlags = append(linkFlags, android.JoinWithPrefix(assetDirs.Strings(), "-A "))
+	linkDeps = append(linkDeps, assetFiles...)
+
+	staticLibs, libDeps, libFlags := aaptLibs(ctx, sdkVersion)
+
+	overlayFiles = append(overlayFiles, staticLibs...)
+	linkDeps = append(linkDeps, libDeps...)
+	linkFlags = append(linkFlags, libFlags...)
+
+	// SDK version flags
+	switch sdkVersion {
+	case "", "current", "system_current", "test_current":
+		sdkVersion = proptools.NinjaEscape([]string{ctx.Config().AppsDefaultVersionName()})[0]
+	}
+
+	linkFlags = append(linkFlags, "--min-sdk-version "+sdkVersion)
+	linkFlags = append(linkFlags, "--target-sdk-version "+sdkVersion)
+
+	// Product characteristics
+	if !hasProduct && len(ctx.Config().ProductAAPTCharacteristics()) > 0 {
+		linkFlags = append(linkFlags, "--product", ctx.Config().ProductAAPTCharacteristics())
+	}
+
+	// Product AAPT config
+	for _, aaptConfig := range ctx.Config().ProductAAPTConfig() {
+		linkFlags = append(linkFlags, "-c", aaptConfig)
+	}
+
+	// Product AAPT preferred config
+	if len(ctx.Config().ProductAAPTPreferredConfig()) > 0 {
+		linkFlags = append(linkFlags, "--preferred-density", ctx.Config().ProductAAPTPreferredConfig())
+	}
+
+	// Version code
+	if !hasVersionCode {
+		linkFlags = append(linkFlags, "--version-code", ctx.Config().PlatformSdkVersion())
+	}
+
+	if !hasVersionName {
+		versionName := proptools.NinjaEscape([]string{ctx.Config().AppsDefaultVersionName()})[0]
+		linkFlags = append(linkFlags, "--version-name ", versionName)
+	}
+
+	return linkFlags, linkDeps, resDirs, overlayDirs, overlayFiles, rroDirs, manifestPath
+}
+
+func (a *aapt) deps(ctx android.BottomUpMutatorContext, sdkVersion string) {
+	if !ctx.Config().UnbundledBuild() {
+		sdkDep := decodeSdkDep(ctx, sdkVersion)
+		if sdkDep.frameworkResModule != "" {
+			ctx.AddDependency(ctx.Module(), frameworkResTag, sdkDep.frameworkResModule)
+		}
+	}
+}
+
+func (a *aapt) buildActions(ctx android.ModuleContext, sdkVersion string, extraLinkFlags ...string) {
+	linkFlags, linkDeps, resDirs, overlayDirs, overlayFiles, rroDirs, manifestPath := a.aapt2Flags(ctx, sdkVersion)
+
+	linkFlags = append(linkFlags, extraLinkFlags...)
+
+	packageRes := android.PathForModuleOut(ctx, "package-res.apk")
+	srcJar := android.PathForModuleGen(ctx, "R.jar")
+	proguardOptionsFile := android.PathForModuleGen(ctx, "proguard.options")
+	rTxt := android.PathForModuleOut(ctx, "R.txt")
+
+	var compiledRes, compiledOverlay android.Paths
+	for _, dir := range resDirs {
+		compiledRes = append(compiledRes, aapt2Compile(ctx, dir.dir, dir.files).Paths()...)
+	}
+	for _, dir := range overlayDirs {
+		compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir.dir, dir.files).Paths()...)
+	}
+
+	compiledOverlay = append(compiledOverlay, overlayFiles...)
+
+	aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile, rTxt,
+		linkFlags, linkDeps, compiledRes, compiledOverlay)
+
+	a.aaptSrcJar = srcJar
+	a.exportPackage = packageRes
+	a.manifestPath = manifestPath
+	a.proguardOptionsFile = proguardOptionsFile
+	a.rroDirs = rroDirs
+	a.rTxt = rTxt
+}
+
+// aaptLibs collects libraries from dependencies and sdk_version and converts them into paths
+func aaptLibs(ctx android.ModuleContext, sdkVersion string) (staticLibs, deps android.Paths, flags []string) {
+	var sharedLibs android.Paths
+
+	sdkDep := decodeSdkDep(ctx, sdkVersion)
+	if sdkDep.useFiles {
+		sharedLibs = append(sharedLibs, sdkDep.jar)
+	}
+
+	ctx.VisitDirectDeps(func(module android.Module) {
+		var exportPackage android.Path
+		if aarDep, ok := module.(AndroidLibraryDependency); ok {
+			exportPackage = aarDep.ExportPackage()
+		}
+
+		switch ctx.OtherModuleDependencyTag(module) {
+		case libTag, frameworkResTag:
+			if exportPackage != nil {
+				sharedLibs = append(sharedLibs, exportPackage)
+			}
+		case staticLibTag:
+			if exportPackage != nil {
+				staticLibs = append(staticLibs, exportPackage)
+			}
+		}
+	})
+
+	deps = append(deps, sharedLibs...)
+	deps = append(deps, staticLibs...)
+
+	if len(staticLibs) > 0 {
+		flags = append(flags, "--auto-add-overlay")
+	}
+
+	for _, sharedLib := range sharedLibs {
+		flags = append(flags, "-I "+sharedLib.String())
+	}
+
+	return staticLibs, deps, flags
+}
+
+type AndroidLibrary struct {
+	Library
+	aapt
+
+	androidLibraryProperties androidLibraryProperties
+
+	aarFile android.WritablePath
+}
+
+var _ AndroidLibraryDependency = (*AndroidLibrary)(nil)
+
+func (a *AndroidLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
+	a.Module.deps(ctx)
+	if !Bool(a.properties.No_framework_libs) && !Bool(a.properties.No_standard_libs) {
+		a.aapt.deps(ctx, String(a.deviceProperties.Sdk_version))
+	}
+}
+
+func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	a.aapt.buildActions(ctx, String(a.deviceProperties.Sdk_version), "--static-lib")
+
+	ctx.CheckbuildFile(a.proguardOptionsFile)
+	ctx.CheckbuildFile(a.exportPackage)
+	ctx.CheckbuildFile(a.aaptSrcJar)
+
+	// apps manifests are handled by aapt, don't let Module see them
+	a.properties.Manifest = nil
+
+	a.Module.extraProguardFlagFiles = append(a.Module.extraProguardFlagFiles,
+		a.proguardOptionsFile)
+
+	a.Module.compile(ctx, a.aaptSrcJar)
+
+	a.aarFile = android.PathForOutput(ctx, ctx.ModuleName()+".aar")
+	var res android.Paths
+	if a.androidLibraryProperties.BuildAAR {
+		BuildAAR(ctx, a.aarFile, a.outputFile, a.manifestPath, a.rTxt, res)
+		ctx.CheckbuildFile(a.aarFile)
+	}
+}
+
+func AndroidLibraryFactory() android.Module {
+	module := &AndroidLibrary{}
+
+	module.AddProperties(
+		&module.Module.properties,
+		&module.Module.deviceProperties,
+		&module.Module.protoProperties,
+		&module.aaptProperties,
+		&module.androidLibraryProperties)
+
+	module.androidLibraryProperties.BuildAAR = true
+
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	return module
+}
+
 //
 // AAR (android library) prebuilts
 //
-func init() {
-	android.RegisterModuleType("android_library_import", AARImportFactory)
-}
 
 type AARImportProperties struct {
 	Aars []string
 
 	Sdk_version *string
+
+	Static_libs []string
+	Libs        []string
 }
 
 type AARImport struct {
@@ -44,6 +330,12 @@
 	exportPackage android.WritablePath
 }
 
+var _ AndroidLibraryDependency = (*AARImport)(nil)
+
+func (a *AARImport) ExportPackage() android.Path {
+	return a.exportPackage
+}
+
 func (a *AARImport) Prebuilt() *android.Prebuilt {
 	return &a.prebuilt
 }
@@ -53,13 +345,15 @@
 }
 
 func (a *AARImport) DepsMutator(ctx android.BottomUpMutatorContext) {
-	// TODO: this should use decodeSdkDep once that knows about current
 	if !ctx.Config().UnbundledBuild() {
-		switch String(a.properties.Sdk_version) { // TODO: Res_sdk_version?
-		case "current", "system_current", "test_current", "":
-			ctx.AddDependency(ctx.Module(), frameworkResTag, "framework-res")
+		sdkDep := decodeSdkDep(ctx, String(a.properties.Sdk_version))
+		if sdkDep.useModule && sdkDep.frameworkResModule != "" {
+			ctx.AddDependency(ctx.Module(), frameworkResTag, sdkDep.frameworkResModule)
 		}
 	}
+
+	ctx.AddDependency(ctx.Module(), staticLibTag, a.properties.Libs...)
+	ctx.AddDependency(ctx.Module(), staticLibTag, a.properties.Static_libs...)
 }
 
 // Unzip an AAR into its constituent files and directories.  Any files in Outputs that don't exist in the AAR will be
@@ -105,6 +399,7 @@
 	a.exportPackage = android.PathForModuleOut(ctx, "package-res.apk")
 	srcJar := android.PathForModuleGen(ctx, "R.jar")
 	proguardOptionsFile := android.PathForModuleGen(ctx, "proguard.options")
+	rTxt := android.PathForModuleOut(ctx, "R.txt")
 
 	var linkDeps android.Paths
 
@@ -117,30 +412,15 @@
 	linkFlags = append(linkFlags, "--manifest "+manifest.String())
 	linkDeps = append(linkDeps, manifest)
 
-	// Include dirs
-	ctx.VisitDirectDeps(func(module android.Module) {
-		var depFiles android.Paths
-		if javaDep, ok := module.(Dependency); ok {
-			// TODO: shared android libraries
-			if ctx.OtherModuleName(module) == "framework-res" {
-				depFiles = android.Paths{javaDep.(*AndroidApp).exportPackage}
-			}
-		}
+	staticLibs, libDeps, libFlags := aaptLibs(ctx, String(a.properties.Sdk_version))
 
-		for _, dep := range depFiles {
-			linkFlags = append(linkFlags, "-I "+dep.String())
-		}
-		linkDeps = append(linkDeps, depFiles...)
-	})
+	linkDeps = append(linkDeps, libDeps...)
+	linkFlags = append(linkFlags, libFlags...)
 
-	sdkDep := decodeSdkDep(ctx, String(a.properties.Sdk_version))
-	if sdkDep.useFiles {
-		linkFlags = append(linkFlags, "-I "+sdkDep.jar.String())
-		linkDeps = append(linkDeps, sdkDep.jar)
-	}
+	overlayRes := append(android.Paths{flata}, staticLibs...)
 
-	aapt2Link(ctx, a.exportPackage, srcJar, proguardOptionsFile,
-		linkFlags, linkDeps, nil, android.Paths{flata})
+	aapt2Link(ctx, a.exportPackage, srcJar, proguardOptionsFile, rTxt,
+		linkFlags, linkDeps, nil, overlayRes)
 }
 
 var _ Dependency = (*AARImport)(nil)
diff --git a/java/android_resources.go b/java/android_resources.go
new file mode 100644
index 0000000..47535d2
--- /dev/null
+++ b/java/android_resources.go
@@ -0,0 +1,127 @@
+// 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 (
+	"path/filepath"
+	"strings"
+
+	"android/soong/android"
+)
+
+func init() {
+	android.RegisterPreSingletonType("overlay", OverlaySingletonFactory)
+}
+
+var androidResourceIgnoreFilenames = []string{
+	".svn",
+	".git",
+	".ds_store",
+	"*.scc",
+	".*",
+	"CVS",
+	"thumbs.db",
+	"picasa.ini",
+	"*~",
+}
+
+func androidResourceGlob(ctx android.ModuleContext, dir android.Path) android.Paths {
+	return ctx.GlobFiles(filepath.Join(dir.String(), "**/*"), androidResourceIgnoreFilenames)
+}
+
+type overlayGlobResult struct {
+	dir   string
+	paths android.DirectorySortedPaths
+
+	// Set to true of the product has selected that values in this overlay should not be moved to
+	// Runtime Resource Overlay (RRO) packages.
+	excludeFromRRO bool
+}
+
+const overlayDataKey = "overlayDataKey"
+
+type globbedResourceDir struct {
+	dir   android.Path
+	files android.Paths
+}
+
+func overlayResourceGlob(ctx android.ModuleContext, dir android.Path) (res []globbedResourceDir,
+	rroDirs android.Paths) {
+
+	overlayData := ctx.Config().Get(overlayDataKey).([]overlayGlobResult)
+
+	// Runtime resource overlays (RRO) may be turned on by the product config for some modules
+	rroEnabled := ctx.Config().EnforceRROForModule(ctx.ModuleName())
+
+	for _, data := range overlayData {
+		files := data.paths.PathsInDirectory(filepath.Join(data.dir, dir.String()))
+		if len(files) > 0 {
+			overlayModuleDir := android.PathForSource(ctx, data.dir, dir.String())
+			// If enforce RRO is enabled for this module and this overlay is not in the
+			// exclusion list, ignore the overlay.  The list of ignored overlays will be
+			// passed to Make to be turned into an RRO package.
+			if rroEnabled && !data.excludeFromRRO {
+				rroDirs = append(rroDirs, overlayModuleDir)
+			} else {
+				res = append(res, globbedResourceDir{
+					dir:   overlayModuleDir,
+					files: files,
+				})
+			}
+		}
+	}
+
+	return res, rroDirs
+}
+
+func OverlaySingletonFactory() android.Singleton {
+	return overlaySingleton{}
+}
+
+type overlaySingleton struct{}
+
+func (overlaySingleton) GenerateBuildActions(ctx android.SingletonContext) {
+	var overlayData []overlayGlobResult
+	overlayDirs := ctx.Config().ResourceOverlays()
+	for i := range overlayDirs {
+		// Iterate backwards through the list of overlay directories so that the later, lower-priority
+		// directories in the list show up earlier in the command line to aapt2.
+		overlay := overlayDirs[len(overlayDirs)-1-i]
+		var result overlayGlobResult
+		result.dir = overlay
+
+		// Mark overlays that will not have Runtime Resource Overlays enforced on them
+		// based on the product config
+		result.excludeFromRRO = ctx.Config().EnforceRROExcludedOverlay(overlay)
+
+		files, err := ctx.GlobWithDeps(filepath.Join(overlay, "**/*"), androidResourceIgnoreFilenames)
+		if err != nil {
+			ctx.Errorf("failed to glob resource dir %q: %s", overlay, err.Error())
+			continue
+		}
+		var paths android.Paths
+		for _, f := range files {
+			if !strings.HasSuffix(f, "/") {
+				paths = append(paths, android.PathForSource(ctx, f))
+			}
+		}
+		result.paths = android.PathsToDirectorySortedPaths(paths)
+		overlayData = append(overlayData, result)
+	}
+
+	ctx.Config().Once(overlayDataKey, func() interface{} {
+		return overlayData
+	})
+}
diff --git a/java/androidmk.go b/java/androidmk.go
index 204b3d9..dfbe7fa 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -223,7 +223,31 @@
 			},
 		},
 	}
+}
 
+func (a *AndroidLibrary) AndroidMk() android.AndroidMkData {
+	data := a.Library.AndroidMk()
+
+	data.Extra = append(data.Extra, func(w io.Writer, outputFile android.Path) {
+		if a.proguardDictionary != nil {
+			fmt.Fprintln(w, "LOCAL_SOONG_PROGUARD_DICT :=", a.proguardDictionary.String())
+		}
+
+		if a.Name() == "framework-res" {
+			fmt.Fprintln(w, "LOCAL_MODULE_PATH := $(TARGET_OUT_JAVA_LIBRARIES)")
+			// Make base_rules.mk not put framework-res in a subdirectory called
+			// framework_res.
+			fmt.Fprintln(w, "LOCAL_NO_STANDARD_LIBRARIES := true")
+		}
+
+		fmt.Fprintln(w, "LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE :=", a.exportPackage.String())
+		fmt.Fprintln(w, "LOCAL_FULL_MANIFEST_FILE :=", a.manifestPath.String())
+		fmt.Fprintln(w, "LOCAL_SOONG_EXPORT_PROGUARD_FLAGS :=", a.proguardOptionsFile.String())
+		fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
+		fmt.Fprintln(w, "LOCAL_DEX_PREOPT := false")
+	})
+
+	return data
 }
 
 func (jd *Javadoc) AndroidMk() android.AndroidMkData {
diff --git a/java/app.go b/java/app.go
index c94d22f..3e24ebc 100644
--- a/java/app.go
+++ b/java/app.go
@@ -17,7 +17,6 @@
 // This file contains the module types for compiling Android apps.
 
 import (
-	"path/filepath"
 	"strings"
 
 	"github.com/google/blueprint/proptools"
@@ -26,11 +25,9 @@
 )
 
 func init() {
-	android.RegisterPreSingletonType("overlay", OverlaySingletonFactory)
 	android.RegisterModuleType("android_app", AndroidAppFactory)
 }
 
-// AAR prebuilts
 // AndroidManifest.xml merging
 // package splits
 
@@ -46,91 +43,59 @@
 	// use to get PRODUCT-agnostic resource data like IDs and type definitions.
 	Export_package_resources *bool
 
-	// flags passed to aapt when creating the apk
-	Aaptflags []string
-
-	// list of resource labels to generate individual resource packages
-	Package_splits []string
-
-	// list of directories relative to the Blueprints file containing assets.
-	// Defaults to "assets"
-	Asset_dirs []string
-
-	// list of directories relative to the Blueprints file containing
-	// Android resources
-	Resource_dirs []string
-
-	Instrumentation_for *string
-
 	// Specifies that this app should be installed to the priv-app directory,
 	// where the system will grant it additional privileges not available to
 	// normal apps.
 	Privileged *bool
+
+	// list of resource labels to generate individual resource packages
+	Package_splits []string
+
+	Instrumentation_for *string
 }
 
 type AndroidApp struct {
-	Module
+	Library
+	aapt
+
+	certificate certificate
 
 	appProperties appProperties
-
-	aaptSrcJar    android.Path
-	exportPackage android.Path
-	rroDirs       android.Paths
-	manifestPath  android.Path
-	certificate   certificate
 }
 
+var _ AndroidLibraryDependency = (*AndroidApp)(nil)
+
 type certificate struct {
 	pem, key android.Path
 }
 
 func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) {
 	a.Module.deps(ctx)
-
 	if !Bool(a.properties.No_framework_libs) && !Bool(a.properties.No_standard_libs) {
-		switch String(a.deviceProperties.Sdk_version) { // TODO: Res_sdk_version?
-		case "current", "system_current", "test_current", "":
-			ctx.AddDependency(ctx.Module(), frameworkResTag, "framework-res")
-		default:
-			// We'll already have a dependency on an sdk prebuilt android.jar
-		}
+		a.aapt.deps(ctx, String(a.deviceProperties.Sdk_version))
 	}
 }
 
 func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, manifestPath := a.aapt2Flags(ctx)
-
-	packageRes := android.PathForModuleOut(ctx, "package-res.apk")
-	srcJar := android.PathForModuleGen(ctx, "R.jar")
-	proguardOptionsFile := android.PathForModuleGen(ctx, "proguard.options")
-
-	var compiledRes, compiledOverlay android.Paths
-	for _, dir := range resDirs {
-		compiledRes = append(compiledRes, aapt2Compile(ctx, dir.dir, dir.files).Paths()...)
-	}
-	for _, dir := range overlayDirs {
-		compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir.dir, dir.files).Paths()...)
+	var linkFlags []string
+	if String(a.appProperties.Instrumentation_for) != "" {
+		linkFlags = append(linkFlags,
+			"--rename-instrumentation-target-package",
+			String(a.appProperties.Instrumentation_for))
+	} else {
+		a.properties.Instrument = true
 	}
 
-	aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile,
-		linkFlags, linkDeps, compiledRes, compiledOverlay)
+	// TODO: LOCAL_PACKAGE_OVERRIDES
+	//    $(addprefix --rename-manifest-package , $(PRIVATE_MANIFEST_PACKAGE_NAME)) \
 
-	a.exportPackage = packageRes
-	a.aaptSrcJar = srcJar
-
-	ctx.CheckbuildFile(proguardOptionsFile)
-	ctx.CheckbuildFile(a.exportPackage)
-	ctx.CheckbuildFile(a.aaptSrcJar)
+	a.aapt.buildActions(ctx, String(a.deviceProperties.Sdk_version), linkFlags...)
 
 	// apps manifests are handled by aapt, don't let Module see them
 	a.properties.Manifest = nil
 
-	if String(a.appProperties.Instrumentation_for) == "" {
-		a.properties.Instrument = true
-	}
-
 	a.Module.extraProguardFlagFiles = append(a.Module.extraProguardFlagFiles,
-		proguardOptionsFile)
+		a.proguardOptionsFile)
 
 	if ctx.ModuleName() != "framework-res" {
 		a.Module.compile(ctx, a.aaptSrcJar)
@@ -167,8 +132,6 @@
 	CreateAppPackage(ctx, packageFile, a.exportPackage, a.outputFile, certificates)
 
 	a.outputFile = packageFile
-	a.rroDirs = rroDirs
-	a.manifestPath = manifestPath
 
 	if ctx.ModuleName() == "framework-res" {
 		// framework-res.apk is installed as system/framework/framework-res.apk
@@ -180,152 +143,6 @@
 	}
 }
 
-var aaptIgnoreFilenames = []string{
-	".svn",
-	".git",
-	".ds_store",
-	"*.scc",
-	".*",
-	"CVS",
-	"thumbs.db",
-	"picasa.ini",
-	"*~",
-}
-
-type globbedResourceDir struct {
-	dir   android.Path
-	files android.Paths
-}
-
-func (a *AndroidApp) aapt2Flags(ctx android.ModuleContext) (flags []string, deps android.Paths,
-	resDirs, overlayDirs []globbedResourceDir, rroDirs android.Paths, manifestPath android.Path) {
-
-	hasVersionCode := false
-	hasVersionName := false
-	hasProduct := false
-	for _, f := range a.appProperties.Aaptflags {
-		if strings.HasPrefix(f, "--version-code") {
-			hasVersionCode = true
-		} else if strings.HasPrefix(f, "--version-name") {
-			hasVersionName = true
-		} else if strings.HasPrefix(f, "--product") {
-			hasProduct = true
-		}
-	}
-
-	var linkFlags []string
-
-	// Flags specified in Android.bp
-	linkFlags = append(linkFlags, a.appProperties.Aaptflags...)
-
-	linkFlags = append(linkFlags, "--no-static-lib-packages")
-
-	// Find implicit or explicit asset and resource dirs
-	assetDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.appProperties.Asset_dirs, "assets")
-	resourceDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.appProperties.Resource_dirs, "res")
-
-	var linkDeps android.Paths
-
-	// Glob directories into lists of paths
-	for _, dir := range resourceDirs {
-		resDirs = append(resDirs, globbedResourceDir{
-			dir:   dir,
-			files: resourceGlob(ctx, dir),
-		})
-		resOverlayDirs, resRRODirs := overlayResourceGlob(ctx, dir)
-		overlayDirs = append(overlayDirs, resOverlayDirs...)
-		rroDirs = append(rroDirs, resRRODirs...)
-	}
-
-	var assetFiles android.Paths
-	for _, dir := range assetDirs {
-		assetFiles = append(assetFiles, resourceGlob(ctx, dir)...)
-	}
-
-	// App manifest file
-	var manifestFile string
-	if a.properties.Manifest == nil {
-		manifestFile = "AndroidManifest.xml"
-	} else {
-		manifestFile = *a.properties.Manifest
-	}
-
-	manifestPath = android.PathForModuleSrc(ctx, manifestFile)
-	linkFlags = append(linkFlags, "--manifest "+manifestPath.String())
-	linkDeps = append(linkDeps, manifestPath)
-
-	linkFlags = append(linkFlags, android.JoinWithPrefix(assetDirs.Strings(), "-A "))
-	linkDeps = append(linkDeps, assetFiles...)
-
-	// Include dirs
-	ctx.VisitDirectDeps(func(module android.Module) {
-		var depFiles android.Paths
-		if javaDep, ok := module.(Dependency); ok {
-			// TODO: shared android libraries
-			if ctx.OtherModuleName(module) == "framework-res" {
-				depFiles = android.Paths{javaDep.(*AndroidApp).exportPackage}
-			}
-		}
-
-		for _, dep := range depFiles {
-			linkFlags = append(linkFlags, "-I "+dep.String())
-		}
-		linkDeps = append(linkDeps, depFiles...)
-	})
-
-	sdkDep := decodeSdkDep(ctx, String(a.deviceProperties.Sdk_version))
-	if sdkDep.useFiles {
-		linkFlags = append(linkFlags, "-I "+sdkDep.jar.String())
-		linkDeps = append(linkDeps, sdkDep.jar)
-	}
-
-	// SDK version flags
-	sdkVersion := String(a.deviceProperties.Sdk_version)
-	switch sdkVersion {
-	case "", "current", "system_current", "test_current":
-		sdkVersion = proptools.NinjaEscape([]string{ctx.Config().AppsDefaultVersionName()})[0]
-	}
-
-	linkFlags = append(linkFlags, "--min-sdk-version "+sdkVersion)
-	linkFlags = append(linkFlags, "--target-sdk-version "+sdkVersion)
-
-	// Product characteristics
-	if !hasProduct && len(ctx.Config().ProductAAPTCharacteristics()) > 0 {
-		linkFlags = append(linkFlags, "--product", ctx.Config().ProductAAPTCharacteristics())
-	}
-
-	// Product AAPT config
-	for _, aaptConfig := range ctx.Config().ProductAAPTConfig() {
-		linkFlags = append(linkFlags, "-c", aaptConfig)
-	}
-
-	// Product AAPT preferred config
-	if len(ctx.Config().ProductAAPTPreferredConfig()) > 0 {
-		linkFlags = append(linkFlags, "--preferred-density", ctx.Config().ProductAAPTPreferredConfig())
-	}
-
-	// Version code
-	if !hasVersionCode {
-		linkFlags = append(linkFlags, "--version-code", ctx.Config().PlatformSdkVersion())
-	}
-
-	if !hasVersionName {
-		versionName := proptools.NinjaEscape([]string{ctx.Config().AppsDefaultVersionName()})[0]
-		linkFlags = append(linkFlags, "--version-name ", versionName)
-	}
-
-	if String(a.appProperties.Instrumentation_for) != "" {
-		linkFlags = append(linkFlags,
-			"--rename-instrumentation-target-package",
-			String(a.appProperties.Instrumentation_for))
-	}
-
-	// TODO: LOCAL_PACKAGE_OVERRIDES
-	//    $(addprefix --rename-manifest-package , $(PRIVATE_MANIFEST_PACKAGE_NAME)) \
-
-	return linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, manifestPath
-}
-
 func AndroidAppFactory() android.Module {
 	module := &AndroidApp{}
 
@@ -335,92 +152,10 @@
 	module.AddProperties(
 		&module.Module.properties,
 		&module.Module.deviceProperties,
+		&module.Module.protoProperties,
+		&module.aaptProperties,
 		&module.appProperties)
 
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
 	return module
 }
-
-func resourceGlob(ctx android.ModuleContext, dir android.Path) android.Paths {
-	return ctx.GlobFiles(filepath.Join(dir.String(), "**/*"), aaptIgnoreFilenames)
-}
-
-type overlayGlobResult struct {
-	dir   string
-	paths android.DirectorySortedPaths
-
-	// Set to true of the product has selected that values in this overlay should not be moved to
-	// Runtime Resource Overlay (RRO) packages.
-	excludeFromRRO bool
-}
-
-const overlayDataKey = "overlayDataKey"
-
-func overlayResourceGlob(ctx android.ModuleContext, dir android.Path) (res []globbedResourceDir,
-	rroDirs android.Paths) {
-
-	overlayData := ctx.Config().Get(overlayDataKey).([]overlayGlobResult)
-
-	// Runtime resource overlays (RRO) may be turned on by the product config for some modules
-	rroEnabled := ctx.Config().EnforceRROForModule(ctx.ModuleName())
-
-	for _, data := range overlayData {
-		files := data.paths.PathsInDirectory(filepath.Join(data.dir, dir.String()))
-		if len(files) > 0 {
-			overlayModuleDir := android.PathForSource(ctx, data.dir, dir.String())
-			// If enforce RRO is enabled for this module and this overlay is not in the
-			// exclusion list, ignore the overlay.  The list of ignored overlays will be
-			// passed to Make to be turned into an RRO package.
-			if rroEnabled && !data.excludeFromRRO {
-				rroDirs = append(rroDirs, overlayModuleDir)
-			} else {
-				res = append(res, globbedResourceDir{
-					dir:   overlayModuleDir,
-					files: files,
-				})
-			}
-		}
-	}
-
-	return res, rroDirs
-}
-
-func OverlaySingletonFactory() android.Singleton {
-	return overlaySingleton{}
-}
-
-type overlaySingleton struct{}
-
-func (overlaySingleton) GenerateBuildActions(ctx android.SingletonContext) {
-	var overlayData []overlayGlobResult
-	overlayDirs := ctx.Config().ResourceOverlays()
-	for i := range overlayDirs {
-		// Iterate backwards through the list of overlay directories so that the later, lower-priority
-		// directories in the list show up earlier in the command line to aapt2.
-		overlay := overlayDirs[len(overlayDirs)-1-i]
-		var result overlayGlobResult
-		result.dir = overlay
-
-		// Mark overlays that will not have Runtime Resource Overlays enforced on them
-		// based on the product config
-		result.excludeFromRRO = ctx.Config().EnforceRROExcludedOverlay(overlay)
-
-		files, err := ctx.GlobWithDeps(filepath.Join(overlay, "**/*"), aaptIgnoreFilenames)
-		if err != nil {
-			ctx.Errorf("failed to glob resource dir %q: %s", overlay, err.Error())
-			continue
-		}
-		var paths android.Paths
-		for _, f := range files {
-			if !strings.HasSuffix(f, "/") {
-				paths = append(paths, android.PathForSource(ctx, f))
-			}
-		}
-		result.paths = android.PathsToDirectorySortedPaths(paths)
-		overlayData = append(overlayData, result)
-	}
-
-	ctx.Config().Once(overlayDataKey, func() interface{} {
-		return overlayData
-	})
-}
diff --git a/java/app_builder.go b/java/app_builder.go
index 945d7bd..954ca44 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -96,3 +96,39 @@
 		},
 	})
 }
+
+var buildAAR = pctx.AndroidStaticRule("buildAAR",
+	blueprint.RuleParams{
+		Command: `rm -rf ${outDir} && mkdir -p ${outDir} && ` +
+			`cp ${manifest} ${outDir}/AndroidManifest.xml && ` +
+			`cp ${classesJar} ${outDir}/classes.jar && ` +
+			`cp ${rTxt} ${outDir}/R.txt && ` +
+			`${config.SoongZipCmd} -jar -o $out -C ${outDir} -D ${outDir} ${resArgs}`,
+		CommandDeps: []string{"${config.SoongZipCmd}"},
+	},
+	"manifest", "classesJar", "rTxt", "resArgs", "outDir")
+
+func BuildAAR(ctx android.ModuleContext, outputFile android.WritablePath,
+	classesJar, manifest, rTxt android.Path, res android.Paths) {
+
+	// TODO(ccross): uniquify and copy resources with dependencies
+
+	deps := android.Paths{manifest, rTxt}
+	classesJarPath := ""
+	if classesJar != nil {
+		deps = append(deps, classesJar)
+		classesJarPath = classesJar.String()
+	}
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:      buildAAR,
+		Implicits: deps,
+		Output:    outputFile,
+		Args: map[string]string{
+			"manifest":   manifest.String(),
+			"classesJar": classesJarPath,
+			"rTxt":       rTxt.String(),
+			"outDir":     android.PathForModuleOut(ctx, "aar").String(),
+		},
+	})
+}
diff --git a/java/app_test.go b/java/app_test.go
index ba017a1..7a61771 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -59,41 +59,44 @@
 }
 
 func TestApp(t *testing.T) {
-	ctx := testApp(t, `
-		android_app {
-			name: "foo",
-			srcs: ["a.java"],
-		}
-	`)
+	for _, moduleType := range []string{"android_app", "android_library"} {
+		t.Run(moduleType, func(t *testing.T) {
+			ctx := testApp(t, moduleType+` {
+					name: "foo",
+					srcs: ["a.java"],
+				}
+			`)
 
-	foo := ctx.ModuleForTests("foo", "android_common")
+			foo := ctx.ModuleForTests("foo", "android_common")
 
-	expectedLinkImplicits := []string{"AndroidManifest.xml"}
+			expectedLinkImplicits := []string{"AndroidManifest.xml"}
 
-	frameworkRes := ctx.ModuleForTests("framework-res", "android_common")
-	expectedLinkImplicits = append(expectedLinkImplicits,
-		frameworkRes.Output("package-res.apk").Output.String())
+			frameworkRes := ctx.ModuleForTests("framework-res", "android_common")
+			expectedLinkImplicits = append(expectedLinkImplicits,
+				frameworkRes.Output("package-res.apk").Output.String())
 
-	// Test the mapping from input files to compiled output file names
-	compile := foo.Output(compiledResourceFiles[0])
-	if !reflect.DeepEqual(resourceFiles, compile.Inputs.Strings()) {
-		t.Errorf("expected aapt2 compile inputs expected:\n  %#v\n got:\n  %#v",
-			resourceFiles, compile.Inputs.Strings())
-	}
+			// Test the mapping from input files to compiled output file names
+			compile := foo.Output(compiledResourceFiles[0])
+			if !reflect.DeepEqual(resourceFiles, compile.Inputs.Strings()) {
+				t.Errorf("expected aapt2 compile inputs expected:\n  %#v\n got:\n  %#v",
+					resourceFiles, compile.Inputs.Strings())
+			}
 
-	compiledResourceOutputs := compile.Outputs.Strings()
-	sort.Strings(compiledResourceOutputs)
+			compiledResourceOutputs := compile.Outputs.Strings()
+			sort.Strings(compiledResourceOutputs)
 
-	expectedLinkImplicits = append(expectedLinkImplicits, compiledResourceOutputs...)
+			expectedLinkImplicits = append(expectedLinkImplicits, compiledResourceOutputs...)
 
-	list := foo.Output("aapt2/res.list")
-	expectedLinkImplicits = append(expectedLinkImplicits, list.Output.String())
+			list := foo.Output("aapt2/res.list")
+			expectedLinkImplicits = append(expectedLinkImplicits, list.Output.String())
 
-	// Check that the link rule uses
-	res := ctx.ModuleForTests("foo", "android_common").Output("package-res.apk")
-	if !reflect.DeepEqual(expectedLinkImplicits, res.Implicits.Strings()) {
-		t.Errorf("expected aapt2 link implicits expected:\n  %#v\n got:\n  %#v",
-			expectedLinkImplicits, res.Implicits.Strings())
+			// Check that the link rule uses
+			res := ctx.ModuleForTests("foo", "android_common").Output("package-res.apk")
+			if !reflect.DeepEqual(expectedLinkImplicits, res.Implicits.Strings()) {
+				t.Errorf("expected aapt2 link implicits expected:\n  %#v\n got:\n  %#v",
+					expectedLinkImplicits, res.Implicits.Strings())
+			}
+		})
 	}
 }
 
diff --git a/java/genrule.go b/java/genrule.go
index 80b7030..8f29482 100644
--- a/java/genrule.go
+++ b/java/genrule.go
@@ -21,6 +21,7 @@
 
 func init() {
 	android.RegisterModuleType("java_genrule", genRuleFactory)
+	android.RegisterModuleType("java_genrule_host", genRuleFactoryHost)
 }
 
 // java_genrule is a genrule that can depend on other java_* objects.
@@ -33,3 +34,14 @@
 
 	return module
 }
+
+// java_genrule_host is a genrule that can depend on other java_* objects.
+// The cmd may be run multiple times, once for each of the different host/device
+// variations.
+func genRuleFactoryHost() android.Module {
+	module := genrule.NewGenRule()
+
+	android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommon)
+
+	return module
+}
diff --git a/java/java.go b/java/java.go
index 04ce469..bc58df3 100644
--- a/java/java.go
+++ b/java/java.go
@@ -334,6 +334,8 @@
 	module        string
 	systemModules string
 
+	frameworkResModule string
+
 	jar  android.Path
 	aidl android.Path
 }
@@ -423,11 +425,12 @@
 		}
 	}
 
-	toModule := func(m string) sdkDep {
+	toModule := func(m, r string) sdkDep {
 		ret := sdkDep{
-			useModule:     true,
-			module:        m,
-			systemModules: m + "_system_modules",
+			useModule:          true,
+			module:             m,
+			systemModules:      m + "_system_modules",
+			frameworkResModule: r,
 		}
 		if m == "core.current.stubs" {
 			ret.systemModules = "core-system-modules"
@@ -442,16 +445,17 @@
 	switch v {
 	case "":
 		return sdkDep{
-			useDefaultLibs: true,
+			useDefaultLibs:     true,
+			frameworkResModule: "framework-res",
 		}
 	case "current":
-		return toModule("android_stubs_current")
+		return toModule("android_stubs_current", "framework-res")
 	case "system_current":
-		return toModule("android_system_stubs_current")
+		return toModule("android_system_stubs_current", "framework-res")
 	case "test_current":
-		return toModule("android_test_stubs_current")
+		return toModule("android_test_stubs_current", "framework-res")
 	case "core_current":
-		return toModule("core.current.stubs")
+		return toModule("core.current.stubs", "")
 	default:
 		return toFile(v)
 	}
@@ -681,7 +685,10 @@
 		tag := ctx.OtherModuleDependencyTag(module)
 
 		if to, ok := module.(*Library); ok {
-			checkLinkType(ctx, j, to, tag.(dependencyTag))
+			switch tag {
+			case bootClasspathTag, libTag, staticLibTag:
+				checkLinkType(ctx, j, to, tag.(dependencyTag))
+			}
 		}
 		switch dep := module.(type) {
 		case Dependency:
diff --git a/java/resources.go b/java/java_resources.go
similarity index 100%
rename from java/resources.go
rename to java/java_resources.go
diff --git a/java/java_test.go b/java/java_test.go
index a85778f..0e7bb18 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -70,6 +70,7 @@
 
 	ctx := android.NewTestArchContext()
 	ctx.RegisterModuleType("android_app", android.ModuleFactoryAdaptor(AndroidAppFactory))
+	ctx.RegisterModuleType("android_library", android.ModuleFactoryAdaptor(AndroidLibraryFactory))
 	ctx.RegisterModuleType("java_binary_host", android.ModuleFactoryAdaptor(BinaryHostFactory))
 	ctx.RegisterModuleType("java_library", android.ModuleFactoryAdaptor(LibraryFactory(true)))
 	ctx.RegisterModuleType("java_library_host", android.ModuleFactoryAdaptor(LibraryHostFactory))