From a97c5d3f08c1df08c73cee4808feb3c1e015bdc8 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Wed, 28 Mar 2018 14:58:31 -0700 Subject: [PATCH] Add support for android_library modules Add support for compiling android_library modules into AARs, and refactor app support on top of it. Bug: 73724997 Test: app_test.go Change-Id: I1dfac5fffe577c6680bc4709147b2061eb7d819c --- Android.bp | 3 +- java/aapt2.go | 10 +- java/aar.go | 336 +++++++++++++++++++++-- java/android_resources.go | 127 +++++++++ java/androidmk.go | 24 ++ java/app.go | 315 ++------------------- java/app_builder.go | 36 +++ java/app_test.go | 57 ++-- java/java.go | 27 +- java/{resources.go => java_resources.go} | 0 java/java_test.go | 1 + 11 files changed, 576 insertions(+), 360 deletions(-) create mode 100644 java/android_resources.go rename java/{resources.go => java_resources.go} (100%) diff --git a/Android.bp b/Android.bp index ec69df8a7..ad2ad4782 100644 --- a/Android.bp +++ b/Android.bp @@ -219,6 +219,7 @@ bootstrap_go_package { 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 @@ bootstrap_go_package { "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/java/aapt2.go b/java/aapt2.go index fd7388e15..61e9451c4 100644 --- a/java/aapt2.go +++ b/java/aapt2.go @@ -111,7 +111,8 @@ func aapt2CompileDirs(ctx android.ModuleContext, flata android.WritablePath, dir 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 @@ var aapt2LinkRule = pctx.AndroidStaticRule("aapt2Link", }, Restat: true, }, - "flags", "inFlags", "proguardOptions", "genDir", "genJar") + "flags", "inFlags", "proguardOptions", "genDir", "genJar", "rTxt") var fileListToFileRule = pctx.AndroidStaticRule("fileListToFile", blueprint.RuleParams{ @@ -129,7 +130,7 @@ var fileListToFileRule = pctx.AndroidStaticRule("fileListToFile", }) 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 @@ func aapt2Link(ctx android.ModuleContext, 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 0df3632b9..57c752c6e 100644 --- a/java/aar.go +++ b/java/aar.go @@ -16,21 +16,307 @@ package java 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 @@ type AARImport struct { 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) Name() string { } 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 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { 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 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { 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 000000000..47535d299 --- /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 204b3d93a..dfbe7fa75 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -223,7 +223,31 @@ func (app *AndroidApp) AndroidMk() android.AndroidMkData { }, }, } +} +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 c94d22f0c..3e24ebc89 100644 --- a/java/app.go +++ b/java/app.go @@ -17,7 +17,6 @@ package java // This file contains the module types for compiling Android apps. import ( - "path/filepath" "strings" "github.com/google/blueprint/proptools" @@ -26,11 +25,9 @@ import ( ) func init() { - android.RegisterPreSingletonType("overlay", OverlaySingletonFactory) android.RegisterModuleType("android_app", AndroidAppFactory) } -// AAR prebuilts // AndroidManifest.xml merging // package splits @@ -46,91 +43,59 @@ type appProperties struct { // 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 @@ func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) { 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 @@ func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) { } } -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 @@ func AndroidAppFactory() android.Module { 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 945d7bdb3..954ca4464 100644 --- a/java/app_builder.go +++ b/java/app_builder.go @@ -96,3 +96,39 @@ func CreateAppPackage(ctx android.ModuleContext, outputFile android.WritablePath }, }) } + +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 ba017a183..7a6177138 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -59,41 +59,44 @@ func testApp(t *testing.T, bp string) *android.TestContext { } 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/java.go b/java/java.go index 04ce4694a..bc58df3ad 100644 --- a/java/java.go +++ b/java/java.go @@ -334,6 +334,8 @@ type sdkDep struct { module string systemModules string + frameworkResModule string + jar android.Path aidl android.Path } @@ -423,11 +425,12 @@ func decodeSdkDep(ctx android.BaseContext, v string) sdkDep { } } - 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 @@ func decodeSdkDep(ctx android.BaseContext, v string) sdkDep { 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 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { 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 a85778fe4..0e7bb18b2 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -70,6 +70,7 @@ func testContext(config android.Config, bp string, 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))