Merge "Revert "Use PathForSource instead of PathsForSource""
diff --git a/Android.bp b/Android.bp
index f2bc5fb..1d2c516 100644
--- a/Android.bp
+++ b/Android.bp
@@ -215,6 +215,7 @@
     ],
     srcs: [
         "java/aapt2.go",
+        "java/aar.go",
         "java/androidmk.go",
         "java/app_builder.go",
         "java/app.go",
diff --git a/android/paths.go b/android/paths.go
index 3bb5d1b..3d4d3f3 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -195,6 +195,20 @@
 
 // PathsForSource returns Paths rooted from SrcDir
 func PathsForSource(ctx PathContext, paths []string) Paths {
+	if ctx.Config().AllowMissingDependencies() {
+		if modCtx, ok := ctx.(ModuleContext); ok {
+			ret := make(Paths, 0, len(paths))
+			for _, path := range paths {
+				p := ExistentPathForSource(ctx, path)
+				if p.Valid() {
+					ret = append(ret, p.Path())
+				} else {
+					modCtx.AddMissingDependencies([]string{path})
+				}
+			}
+			return ret
+		}
+	}
 	ret := make(Paths, len(paths))
 	for i, path := range paths {
 		ret[i] = PathForSource(ctx, path)
@@ -493,99 +507,99 @@
 	return ret
 }
 
-// pathForSource creates a SourcePath from pathComponents, but does not check that it exists.
-func pathForSource(ctx PathContext, pathComponents ...string) (SourcePath, error) {
-	p, err := validatePath(pathComponents...)
-	ret := SourcePath{basePath{p, ctx.Config(), ""}}
-	if err != nil {
-		return ret, err
-	}
-
-	abs, err := filepath.Abs(ret.String())
-	if err != nil {
-		return ret, err
-	}
-	buildroot, err := filepath.Abs(ctx.Config().buildDir)
-	if err != nil {
-		return ret, err
-	}
-	if strings.HasPrefix(abs, buildroot) {
-		return ret, fmt.Errorf("source path %s is in output", abs)
-	}
-
-	if pathtools.IsGlob(ret.String()) {
-		return ret, fmt.Errorf("path may not contain a glob: %s", ret.String())
-	}
-
-	return ret, nil
-}
-
-// existsWithDependencies returns true if the path exists, and adds appropriate dependencies to rerun if the
-// path does not exist.
-func existsWithDependencies(ctx PathContext, path SourcePath) (exists bool, err error) {
-	var files []string
-
-	if gctx, ok := ctx.(PathGlobContext); ok {
-		// Use glob to produce proper dependencies, even though we only want
-		// a single file.
-		files, err = gctx.GlobWithDeps(path.String(), nil)
-	} else {
-		var deps []string
-		// We cannot add build statements in this context, so we fall back to
-		// AddNinjaFileDeps
-		files, deps, err = pathtools.Glob(path.String(), nil)
-		ctx.AddNinjaFileDeps(deps...)
-	}
-
-	if err != nil {
-		return false, fmt.Errorf("glob: %s", err.Error())
-	}
-
-	return len(files) > 0, nil
-}
-
 // PathForSource joins the provided path components and validates that the result
 // neither escapes the source dir nor is in the out dir.
 // On error, it will return a usable, but invalid SourcePath, and report a ModuleError.
 func PathForSource(ctx PathContext, pathComponents ...string) SourcePath {
-	path, err := pathForSource(ctx, pathComponents...)
+	p, err := validatePath(pathComponents...)
+	ret := SourcePath{basePath{p, ctx.Config(), ""}}
 	if err != nil {
 		reportPathError(ctx, err)
+		return ret
 	}
 
-	if modCtx, ok := ctx.(ModuleContext); ok && ctx.Config().AllowMissingDependencies() {
-		exists, err := existsWithDependencies(ctx, path)
-		if err != nil {
-			reportPathError(ctx, err)
-		}
-		if !exists {
-			modCtx.AddMissingDependencies([]string{path.String()})
-		}
-	} else if exists, _, err := ctx.Fs().Exists(path.String()); err != nil {
-		reportPathErrorf(ctx, "%s: %s", path, err.Error())
-	} else if !exists {
-		reportPathErrorf(ctx, "source path %s does not exist", path)
+	abs, err := filepath.Abs(ret.String())
+	if err != nil {
+		reportPathError(ctx, err)
+		return ret
 	}
-	return path
+	buildroot, err := filepath.Abs(ctx.Config().buildDir)
+	if err != nil {
+		reportPathError(ctx, err)
+		return ret
+	}
+	if strings.HasPrefix(abs, buildroot) {
+		reportPathErrorf(ctx, "source path %s is in output", abs)
+		return ret
+	}
+
+	if exists, _, err := ctx.Fs().Exists(ret.String()); err != nil {
+		reportPathErrorf(ctx, "%s: %s", ret, err.Error())
+	} else if !exists {
+		reportPathErrorf(ctx, "source path %s does not exist", ret)
+	}
+	return ret
 }
 
 // ExistentPathForSource returns an OptionalPath with the SourcePath if the
 // path exists, or an empty OptionalPath if it doesn't exist. Dependencies are added
 // so that the ninja file will be regenerated if the state of the path changes.
 func ExistentPathForSource(ctx PathContext, pathComponents ...string) OptionalPath {
-	path, err := pathForSource(ctx, pathComponents...)
+	p, err := validatePath(pathComponents...)
 	if err != nil {
 		reportPathError(ctx, err)
 		return OptionalPath{}
 	}
+	path := SourcePath{basePath{p, ctx.Config(), ""}}
+
+	abs, err := filepath.Abs(path.String())
+	if err != nil {
+		reportPathError(ctx, err)
+		return OptionalPath{}
+	}
+	buildroot, err := filepath.Abs(ctx.Config().buildDir)
+	if err != nil {
+		reportPathError(ctx, err)
+		return OptionalPath{}
+	}
+	if strings.HasPrefix(abs, buildroot) {
+		reportPathErrorf(ctx, "source path %s is in output", abs)
+		return OptionalPath{}
+	}
 
-	exists, err := existsWithDependencies(ctx, path)
-	if err != nil {
-		reportPathError(ctx, err)
+	if pathtools.IsGlob(path.String()) {
+		reportPathErrorf(ctx, "path may not contain a glob: %s", path.String())
 		return OptionalPath{}
 	}
-	if !exists {
-		return OptionalPath{}
+
+	if gctx, ok := ctx.(PathGlobContext); ok {
+		// Use glob to produce proper dependencies, even though we only want
+		// a single file.
+		files, err := gctx.GlobWithDeps(path.String(), nil)
+		if err != nil {
+			reportPathErrorf(ctx, "glob: %s", err.Error())
+			return OptionalPath{}
+		}
+
+		if len(files) == 0 {
+			return OptionalPath{}
+		}
+	} else {
+		// We cannot add build statements in this context, so we fall back to
+		// AddNinjaFileDeps
+		files, dirs, err := pathtools.Glob(path.String(), nil)
+		if err != nil {
+			reportPathErrorf(ctx, "glob: %s", err.Error())
+			return OptionalPath{}
+		}
+
+		ctx.AddNinjaFileDeps(dirs...)
+
+		if len(files) == 0 {
+			return OptionalPath{}
+		}
+
+		ctx.AddNinjaFileDeps(path.String())
 	}
 	return OptionalPathForPath(path)
 }
diff --git a/androidmk/cmd/androidmk/androidmk.go b/androidmk/cmd/androidmk/androidmk.go
index 385690c..6e0b474 100644
--- a/androidmk/cmd/androidmk/androidmk.go
+++ b/androidmk/cmd/androidmk/androidmk.go
@@ -239,12 +239,12 @@
 	}
 
 	// check for common supported but undesirable structures and clean them up
-	fixed, err := bpfix.FixTree(tree, bpfix.NewFixRequest().AddAll())
+	err := bpfix.FixTree(tree, bpfix.NewFixRequest().AddAll())
 	if err != nil {
 		return "", []error{err}
 	}
 
-	out, err := bpparser.Print(fixed)
+	out, err := bpparser.Print(tree)
 	if err != nil {
 		return "", []error{err}
 	}
diff --git a/androidmk/cmd/androidmk/androidmk_test.go b/androidmk/cmd/androidmk/androidmk_test.go
index 3252791..45df1a5 100644
--- a/androidmk/cmd/androidmk/androidmk_test.go
+++ b/androidmk/cmd/androidmk/androidmk_test.go
@@ -492,6 +492,36 @@
 			}
 		`,
 	},
+	{
+		desc: "java prebuilt",
+		in: `
+			include $(CLEAR_VARS)
+			LOCAL_SRC_FILES := test.jar
+			LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+			include $(BUILD_PREBUILT)
+		`,
+		expected: `
+			java_import {
+				jars: ["test.jar"],
+
+			}
+		`,
+	},
+	{
+		desc: "aar prebuilt",
+		in: `
+			include $(CLEAR_VARS)
+			LOCAL_SRC_FILES := test.aar
+			LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+			include $(BUILD_PREBUILT)
+		`,
+		expected: `
+			android_library_import {
+				aars: ["test.aar"],
+
+			}
+		`,
+	},
 }
 
 func reformatBlueprint(input string) string {
diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go
index fcd4fec..2358f0c 100644
--- a/bpfix/bpfix/bpfix.go
+++ b/bpfix/bpfix/bpfix.go
@@ -19,6 +19,7 @@
 import (
 	"bytes"
 	"fmt"
+	"path/filepath"
 
 	"github.com/google/blueprint/parser"
 )
@@ -26,7 +27,8 @@
 // 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
+	simplifyKnownRedundantVariables    bool
+	rewriteIncorrectAndroidmkPrebuilts bool
 }
 
 func NewFixRequest() FixRequest {
@@ -36,25 +38,25 @@
 func (r FixRequest) AddAll() (result FixRequest) {
 	result = r
 	result.simplifyKnownRedundantVariables = true
+	result.rewriteIncorrectAndroidmkPrebuilts = true
 	return result
 }
 
 // FixTree 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) (fixed *parser.File, err error) {
+func FixTree(tree *parser.File, config FixRequest) error {
 	prevIdentifier, err := fingerprint(tree)
 	if err != nil {
-		return nil, err
+		return err
 	}
 
-	fixed = tree
 	maxNumIterations := 20
 	i := 0
 	for {
-		fixed, err = fixTreeOnce(fixed, config)
+		err = fixTreeOnce(tree, config)
 		newIdentifier, err := fingerprint(tree)
 		if err != nil {
-			return nil, err
+			return err
 		}
 		if bytes.Equal(newIdentifier, prevIdentifier) {
 			break
@@ -65,11 +67,11 @@
 		// detect infinite loop
 		i++
 		if i >= maxNumIterations {
-			return nil, fmt.Errorf("Applied fixes %s times and yet the tree continued to change. Is there an infinite loop?", i)
+			return fmt.Errorf("Applied fixes %s times and yet the tree continued to change. Is there an infinite loop?", i)
 			break
 		}
 	}
-	return fixed, err
+	return err
 }
 
 // returns a unique identifier for the given tree that can be used to determine whether the tree changed
@@ -81,20 +83,57 @@
 	return bytes, nil
 }
 
-func fixTreeOnce(tree *parser.File, config FixRequest) (fixed *parser.File, err error) {
+func fixTreeOnce(tree *parser.File, config FixRequest) error {
 	if config.simplifyKnownRedundantVariables {
-		tree, err = simplifyKnownPropertiesDuplicatingEachOther(tree)
+		err := simplifyKnownPropertiesDuplicatingEachOther(tree)
 		if err != nil {
-			return nil, err
+			return err
 		}
 	}
-	return tree, err
+	if config.rewriteIncorrectAndroidmkPrebuilts {
+		err := rewriteIncorrectAndroidmkPrebuilts(tree)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
 }
 
-func simplifyKnownPropertiesDuplicatingEachOther(tree *parser.File) (fixed *parser.File, err error) {
+func simplifyKnownPropertiesDuplicatingEachOther(tree *parser.File) error {
 	// remove from local_include_dirs anything in export_include_dirs
-	fixed, err = removeMatchingModuleListProperties(tree, "export_include_dirs", "local_include_dirs")
-	return fixed, err
+	return removeMatchingModuleListProperties(tree, "export_include_dirs", "local_include_dirs")
+}
+
+func rewriteIncorrectAndroidmkPrebuilts(tree *parser.File) error {
+	for _, def := range tree.Defs {
+		mod, ok := def.(*parser.Module)
+		if !ok {
+			continue
+		}
+		if mod.Type != "java_import" {
+			continue
+		}
+		srcs, ok := getLiteralListProperty(mod, "srcs")
+		if !ok {
+			continue
+		}
+		if len(srcs.Values) == 0 {
+			continue
+		}
+		src, ok := srcs.Values[0].(*parser.String)
+		if !ok {
+			continue
+		}
+		switch filepath.Ext(src.Value) {
+		case ".jar":
+			renameProperty(mod, "srcs", "jars")
+		case ".aar":
+			renameProperty(mod, "srcs", "aars")
+			mod.Type = "android_library_import"
+		}
+	}
+
+	return nil
 }
 
 // removes from <items> every item present in <removals>
@@ -121,29 +160,38 @@
 }
 
 // Remove each modules[i].Properties[<legacyName>][j] that matches a modules[i].Properties[<canonicalName>][k]
-func removeMatchingModuleListProperties(tree *parser.File, canonicalName string, legacyName string) (fixed *parser.File, err error) {
+func removeMatchingModuleListProperties(tree *parser.File, canonicalName string, legacyName string) error {
 	for _, def := range tree.Defs {
 		mod, ok := def.(*parser.Module)
 		if !ok {
 			continue
 		}
-		legacy, ok := mod.GetProperty(legacyName)
+		legacyList, ok := getLiteralListProperty(mod, legacyName)
 		if !ok {
 			continue
 		}
-		legacyList, ok := legacy.Value.(*parser.List)
-		if !ok {
-			continue
-		}
-		canonical, ok := mod.GetProperty(canonicalName)
-		if !ok {
-			continue
-		}
-		canonicalList, ok := canonical.Value.(*parser.List)
+		canonicalList, ok := getLiteralListProperty(mod, canonicalName)
 		if !ok {
 			continue
 		}
 		filterExpressionList(legacyList, canonicalList)
 	}
-	return tree, nil
+	return nil
+}
+
+func getLiteralListProperty(mod *parser.Module, name string) (list *parser.List, found bool) {
+	prop, ok := mod.GetProperty(name)
+	if !ok {
+		return nil, false
+	}
+	list, ok = prop.Value.(*parser.List)
+	return list, ok
+}
+
+func renameProperty(mod *parser.Module, from, to string) {
+	for _, prop := range mod.Properties {
+		if prop.Name == from {
+			prop.Name = to
+		}
+	}
 }
diff --git a/bpfix/bpfix/bpfix_test.go b/bpfix/bpfix/bpfix_test.go
index 06ae139..e17e815 100644
--- a/bpfix/bpfix/bpfix_test.go
+++ b/bpfix/bpfix/bpfix_test.go
@@ -21,8 +21,9 @@
 	"strings"
 	"testing"
 
-	"github.com/google/blueprint/parser"
 	"reflect"
+
+	"github.com/google/blueprint/parser"
 )
 
 // TODO(jeffrygaston) remove this when position is removed from ParseNode (in b/38325146) and we can directly do reflect.DeepEqual
@@ -62,7 +63,7 @@
 	}
 
 	// apply simplifications
-	tree, err := simplifyKnownPropertiesDuplicatingEachOther(tree)
+	err := simplifyKnownPropertiesDuplicatingEachOther(tree)
 	if len(errs) > 0 {
 		t.Fatal(err)
 	}
diff --git a/bpfix/cmd/bpfix.go b/bpfix/cmd/bpfix.go
index f51c6f7..461f41d 100644
--- a/bpfix/cmd/bpfix.go
+++ b/bpfix/cmd/bpfix.go
@@ -75,13 +75,13 @@
 	}
 
 	// compute and apply any requested fixes
-	fixed, err := bpfix.FixTree(file, fixRequest)
+	err = bpfix.FixTree(file, fixRequest)
 	if err != nil {
 		return err
 	}
 
 	// output the results
-	res, err := parser.Print(fixed)
+	res, err := parser.Print(file)
 	if err != nil {
 		return err
 	}
diff --git a/java/aapt2.go b/java/aapt2.go
index 84e3729..fd7388e 100644
--- a/java/aapt2.go
+++ b/java/aapt2.go
@@ -81,6 +81,8 @@
 			Outputs:     outPaths,
 			Args: map[string]string{
 				"outDir": android.PathForModuleOut(ctx, "aapt2", dir.String()).String(),
+				// Always set --pseudo-localize, it will be stripped out later for release
+				// builds that don't want it.
 				"cFlags": "--pseudo-localize",
 			},
 		})
@@ -92,6 +94,21 @@
 	return ret
 }
 
+func aapt2CompileDirs(ctx android.ModuleContext, flata android.WritablePath, dirs android.Paths, deps android.Paths) {
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        aapt2CompileRule,
+		Description: "aapt2 compile dirs",
+		Implicits:   deps,
+		Output:      flata,
+		Args: map[string]string{
+			"outDir": flata.String(),
+			// Always set --pseudo-localize, it will be stripped out later for release
+			// builds that don't want it.
+			"cFlags": "--pseudo-localize " + android.JoinWithPrefix(dirs.Strings(), "--dir "),
+		},
+	})
+}
+
 var aapt2LinkRule = pctx.AndroidStaticRule("aapt2Link",
 	blueprint.RuleParams{
 		Command: `${config.Aapt2Cmd} link -o $out $flags --java $genDir --proguard $proguardOptions $inFlags && ` +
diff --git a/java/aar.go b/java/aar.go
new file mode 100644
index 0000000..0df3632
--- /dev/null
+++ b/java/aar.go
@@ -0,0 +1,170 @@
+// 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"
+
+	"github.com/google/blueprint"
+)
+
+//
+// AAR (android library) prebuilts
+//
+func init() {
+	android.RegisterModuleType("android_library_import", AARImportFactory)
+}
+
+type AARImportProperties struct {
+	Aars []string
+
+	Sdk_version *string
+}
+
+type AARImport struct {
+	android.ModuleBase
+	prebuilt android.Prebuilt
+
+	properties AARImportProperties
+
+	classpathFile android.WritablePath
+	proguardFlags android.WritablePath
+	exportPackage android.WritablePath
+}
+
+func (a *AARImport) Prebuilt() *android.Prebuilt {
+	return &a.prebuilt
+}
+
+func (a *AARImport) Name() string {
+	return a.prebuilt.Name(a.ModuleBase.Name())
+}
+
+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")
+		}
+	}
+}
+
+// Unzip an AAR into its constituent files and directories.  Any files in Outputs that don't exist in the AAR will be
+// touched to create an empty file, and any directories in $expectedDirs will be created.
+var unzipAAR = pctx.AndroidStaticRule("unzipAAR",
+	blueprint.RuleParams{
+		Command: `rm -rf $outDir && mkdir -p $outDir $expectedDirs && ` +
+			`unzip -qo -d $outDir $in && touch $out`,
+	},
+	"expectedDirs", "outDir")
+
+func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	if len(a.properties.Aars) != 1 {
+		ctx.PropertyErrorf("aars", "exactly one aar is required")
+		return
+	}
+
+	aar := android.PathForModuleSrc(ctx, a.properties.Aars[0])
+
+	extractedAARDir := android.PathForModuleOut(ctx, "aar")
+	extractedResDir := extractedAARDir.Join(ctx, "res")
+	a.classpathFile = extractedAARDir.Join(ctx, "classes.jar")
+	a.proguardFlags = extractedAARDir.Join(ctx, "proguard.txt")
+	manifest := extractedAARDir.Join(ctx, "AndroidManifest.xml")
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        unzipAAR,
+		Input:       aar,
+		Outputs:     android.WritablePaths{a.classpathFile, a.proguardFlags, manifest},
+		Description: "unzip AAR",
+		Args: map[string]string{
+			"expectedDirs": extractedResDir.String(),
+			"outDir":       extractedAARDir.String(),
+		},
+	})
+
+	compiledResDir := android.PathForModuleOut(ctx, "flat-res")
+	aaptCompileDeps := android.Paths{a.classpathFile}
+	aaptCompileDirs := android.Paths{extractedResDir}
+	flata := compiledResDir.Join(ctx, "gen_res.flata")
+	aapt2CompileDirs(ctx, flata, aaptCompileDirs, aaptCompileDeps)
+
+	a.exportPackage = android.PathForModuleOut(ctx, "package-res.apk")
+	srcJar := android.PathForModuleGen(ctx, "R.jar")
+	proguardOptionsFile := android.PathForModuleGen(ctx, "proguard.options")
+
+	var linkDeps android.Paths
+
+	linkFlags := []string{
+		"--static-lib",
+		"--no-static-lib-packages",
+		"--auto-add-overlay",
+	}
+
+	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}
+			}
+		}
+
+		for _, dep := range depFiles {
+			linkFlags = append(linkFlags, "-I "+dep.String())
+		}
+		linkDeps = append(linkDeps, depFiles...)
+	})
+
+	sdkDep := decodeSdkDep(ctx, String(a.properties.Sdk_version))
+	if sdkDep.useFiles {
+		linkFlags = append(linkFlags, "-I "+sdkDep.jar.String())
+		linkDeps = append(linkDeps, sdkDep.jar)
+	}
+
+	aapt2Link(ctx, a.exportPackage, srcJar, proguardOptionsFile,
+		linkFlags, linkDeps, nil, android.Paths{flata})
+}
+
+var _ Dependency = (*AARImport)(nil)
+
+func (a *AARImport) HeaderJars() android.Paths {
+	return android.Paths{a.classpathFile}
+}
+
+func (a *AARImport) ImplementationJars() android.Paths {
+	return android.Paths{a.classpathFile}
+}
+
+func (a *AARImport) AidlIncludeDirs() android.Paths {
+	return nil
+}
+
+var _ android.PrebuiltInterface = (*Import)(nil)
+
+func AARImportFactory() android.Module {
+	module := &AARImport{}
+
+	module.AddProperties(&module.properties)
+
+	android.InitPrebuiltModule(module, &module.properties.Aars)
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	return module
+}
diff --git a/java/androidmk.go b/java/androidmk.go
index bb1a13c..3658636 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -112,6 +112,24 @@
 	}
 }
 
+func (prebuilt *AARImport) AndroidMk() android.AndroidMkData {
+	return android.AndroidMkData{
+		Class:      "JAVA_LIBRARIES",
+		OutputFile: android.OptionalPathForPath(prebuilt.classpathFile),
+		Include:    "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
+		Extra: []android.AndroidMkExtraFunc{
+			func(w io.Writer, outputFile android.Path) {
+				fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
+				fmt.Fprintln(w, "LOCAL_DEX_PREOPT := false")
+				fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", prebuilt.classpathFile.String())
+				fmt.Fprintln(w, "LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE :=", prebuilt.exportPackage.String())
+				fmt.Fprintln(w, "LOCAL_SOONG_EXPORT_PROGUARD_FLAGS :=", prebuilt.proguardFlags.String())
+				fmt.Fprintln(w, "LOCAL_SDK_VERSION :=", String(prebuilt.properties.Sdk_version))
+			},
+		},
+	}
+}
+
 func (binary *Binary) AndroidMk() android.AndroidMkData {
 
 	if !binary.isWrapperVariant {
diff --git a/java/app.go b/java/app.go
index 05cd8b3..34f05b7 100644
--- a/java/app.go
+++ b/java/app.go
@@ -34,7 +34,7 @@
 // AndroidManifest.xml merging
 // package splits
 
-type androidAppProperties struct {
+type appProperties struct {
 	// path to a certificate, or the name of a certificate in the default
 	// certificate directory, or blank to use the default product certificate
 	Certificate *string
@@ -71,7 +71,7 @@
 type AndroidApp struct {
 	Module
 
-	appProperties androidAppProperties
+	appProperties appProperties
 
 	aaptSrcJar    android.Path
 	exportPackage android.Path
@@ -273,6 +273,12 @@
 		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 {