diff options
| -rw-r--r-- | Android.bp | 1 | ||||
| -rw-r--r-- | android/paths.go | 136 | ||||
| -rw-r--r-- | androidmk/cmd/androidmk/androidmk.go | 4 | ||||
| -rw-r--r-- | androidmk/cmd/androidmk/androidmk_test.go | 30 | ||||
| -rw-r--r-- | bpfix/bpfix/bpfix.go | 102 | ||||
| -rw-r--r-- | bpfix/bpfix/bpfix_test.go | 5 | ||||
| -rw-r--r-- | bpfix/cmd/bpfix.go | 4 | ||||
| -rw-r--r-- | java/aapt2.go | 17 | ||||
| -rw-r--r-- | java/aar.go | 170 | ||||
| -rw-r--r-- | java/androidmk.go | 18 | ||||
| -rw-r--r-- | java/app.go | 10 |
11 files changed, 401 insertions, 96 deletions
diff --git a/Android.bp b/Android.bp index f2bc5fb91..1d2c5167f 100644 --- a/Android.bp +++ b/Android.bp @@ -215,6 +215,7 @@ bootstrap_go_package { ], 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 3bb5d1b78..3d4d3f30e 100644 --- a/android/paths.go +++ b/android/paths.go @@ -195,6 +195,20 @@ type Paths []Path // 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,100 +507,100 @@ func safePathForSource(ctx PathContext, path string) SourcePath { return ret } -// pathForSource creates a SourcePath from pathComponents, but does not check that it exists. -func pathForSource(ctx PathContext, pathComponents ...string) (SourcePath, error) { +// 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 { p, err := validatePath(pathComponents...) ret := SourcePath{basePath{p, ctx.Config(), ""}} if err != nil { - return ret, err + reportPathError(ctx, err) + return ret } abs, err := filepath.Abs(ret.String()) if err != nil { - return ret, err + reportPathError(ctx, err) + return ret } buildroot, err := filepath.Abs(ctx.Config().buildDir) if err != nil { - return ret, err + reportPathError(ctx, err) + return ret } 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...) - if err != nil { - reportPathError(ctx, err) + reportPathErrorf(ctx, "source path %s is in output", abs) + 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()) + 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", path) + reportPathErrorf(ctx, "source path %s does not exist", ret) } - return path + 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(), ""}} - exists, err := existsWithDependencies(ctx, path) + abs, err := filepath.Abs(path.String()) if err != nil { reportPathError(ctx, err) return OptionalPath{} } - if !exists { + 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{} + } + + if pathtools.IsGlob(path.String()) { + reportPathErrorf(ctx, "path may not contain a glob: %s", path.String()) 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 385690c25..6e0b474bc 100644 --- a/androidmk/cmd/androidmk/androidmk.go +++ b/androidmk/cmd/androidmk/androidmk.go @@ -239,12 +239,12 @@ func convertFile(filename string, buffer *bytes.Buffer) (string, []error) { } // 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 3252791fb..45df1a570 100644 --- a/androidmk/cmd/androidmk/androidmk_test.go +++ b/androidmk/cmd/androidmk/androidmk_test.go @@ -492,6 +492,36 @@ include $(call all-makefiles-under,$(LOCAL_PATH)) } `, }, + { + 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 fcd4fecf7..2358f0cf9 100644 --- a/bpfix/bpfix/bpfix.go +++ b/bpfix/bpfix/bpfix.go @@ -19,6 +19,7 @@ package bpfix import ( "bytes" "fmt" + "path/filepath" "github.com/google/blueprint/parser" ) @@ -26,7 +27,8 @@ import ( // 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 NewFixRequest() FixRequest { 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 @@ func FixTree(tree *parser.File, config FixRequest) (fixed *parser.File, err erro // 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 @@ func fingerprint(tree *parser.File) (fingerprint []byte, err error) { 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 @@ func filterExpressionList(items *parser.List, removals *parser.List) { } // 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) - if !ok { - continue - } - legacyList, ok := legacy.Value.(*parser.List) - if !ok { - continue - } - canonical, ok := mod.GetProperty(canonicalName) + legacyList, ok := getLiteralListProperty(mod, legacyName) 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 06ae13996..e17e815a0 100644 --- a/bpfix/bpfix/bpfix_test.go +++ b/bpfix/bpfix/bpfix_test.go @@ -21,8 +21,9 @@ import ( "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 @@ func implFilterListTest(t *testing.T, local_include_dirs []string, export_includ } // 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 f51c6f715..461f41ddd 100644 --- a/bpfix/cmd/bpfix.go +++ b/bpfix/cmd/bpfix.go @@ -75,13 +75,13 @@ func processFile(filename string, in io.Reader, out io.Writer, fixRequest bpfix. } // 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 84e3729fe..fd7388e15 100644 --- a/java/aapt2.go +++ b/java/aapt2.go @@ -81,6 +81,8 @@ func aapt2Compile(ctx android.ModuleContext, dir android.Path, paths android.Pat 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 @@ func aapt2Compile(ctx android.ModuleContext, dir android.Path, paths android.Pat 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 000000000..0df3632b9 --- /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 bb1a13c56..3658636f8 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -112,6 +112,24 @@ func (prebuilt *Import) AndroidMk() android.AndroidMkData { } } +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 05cd8b31d..34f05b736 100644 --- a/java/app.go +++ b/java/app.go @@ -34,7 +34,7 @@ func init() { // 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 androidAppProperties struct { type AndroidApp struct { Module - appProperties androidAppProperties + appProperties appProperties aaptSrcJar android.Path exportPackage android.Path @@ -273,6 +273,12 @@ func (a *AndroidApp) aapt2Flags(ctx android.ModuleContext) (flags []string, deps 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 { |