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 {