aboutsummaryrefslogtreecommitdiffstats
path: root/java
diff options
context:
space:
mode:
Diffstat (limited to 'java')
-rw-r--r--java/app.go317
-rw-r--r--java/app_builder.go172
2 files changed, 489 insertions, 0 deletions
diff --git a/java/app.go b/java/app.go
new file mode 100644
index 00000000..869cfea0
--- /dev/null
+++ b/java/app.go
@@ -0,0 +1,317 @@
+// Copyright 2015 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
+
+// This file contains the module types for compiling Android apps.
+
+import (
+ "os"
+ "path/filepath"
+ "strings"
+
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/pathtools"
+
+ "android/soong/common"
+)
+
+// AAR prebuilts
+// AndroidManifest.xml merging
+// package splits
+
+type AndroidApp struct {
+ javaBase
+
+ appProperties struct {
+ // certificate: 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
+
+ // additional_certificates: paths to extra certificates to sign the apk with
+ Additional_certificates []string
+
+ // export_package_resources: If set, create package-export.apk, which other packages can
+ // use to get PRODUCT-agnostic resource data like IDs and type definitions.
+ Export_package_resources bool
+
+ // aaptflags: flags passed to aapt when creating the apk
+ Aaptflags []string
+
+ // package_splits: list of resource labels to generate individual resource packages
+ Package_splits []string
+
+ // asset_dirs: list of directories relative to the Blueprints file containing assets.
+ // Defaults to "assets"
+ Asset_dirs []string
+
+ // android_resource_dirs: list of directories relative to the Blueprints file containing
+ // Java resources
+ Android_resource_dirs []string
+ }
+
+ aaptJavaFileList string
+ exportPackage string
+}
+
+func (a *AndroidApp) JavaDynamicDependencies(ctx common.AndroidDynamicDependerModuleContext) []string {
+ deps := a.javaBase.JavaDynamicDependencies(ctx)
+
+ if !a.properties.No_standard_libraries {
+ switch a.properties.Sdk_version { // TODO: Res_sdk_version?
+ case "current", "system_current", "":
+ deps = append(deps, "framework-res")
+ default:
+ // We'll already have a dependency on an sdk prebuilt android.jar
+ }
+ }
+
+ return deps
+}
+
+func (a *AndroidApp) GenerateJavaBuildActions(ctx common.AndroidModuleContext) {
+ aaptFlags, aaptDeps, hasResources := a.aaptFlags(ctx)
+
+ if hasResources {
+ // First generate R.java so we can build the .class files
+ aaptRJavaFlags := append([]string(nil), aaptFlags...)
+
+ publicResourcesFile, proguardOptionsFile, aaptJavaFileList :=
+ CreateResourceJavaFiles(ctx, aaptRJavaFlags, aaptDeps)
+ a.aaptJavaFileList = aaptJavaFileList
+ a.ExtraSrcLists = append(a.ExtraSrcLists, aaptJavaFileList)
+
+ if a.appProperties.Export_package_resources {
+ aaptPackageFlags := append([]string(nil), aaptFlags...)
+ var hasProduct bool
+ for _, f := range aaptPackageFlags {
+ if strings.HasPrefix(f, "--product") {
+ hasProduct = true
+ break
+ }
+ }
+
+ if !hasProduct {
+ aaptPackageFlags = append(aaptPackageFlags,
+ "--product "+ctx.AConfig().ProductAaptCharacteristics())
+ }
+ a.exportPackage = CreateExportPackage(ctx, aaptPackageFlags, aaptDeps)
+ ctx.CheckbuildFile(a.exportPackage)
+ }
+ ctx.CheckbuildFile(publicResourcesFile)
+ ctx.CheckbuildFile(proguardOptionsFile)
+ ctx.CheckbuildFile(aaptJavaFileList)
+ }
+
+ // apps manifests are handled by aapt, don't let javaBase see them
+ a.properties.Manifest = ""
+
+ //if !ctx.ContainsProperty("proguard.enabled") {
+ // a.properties.Proguard.Enabled = true
+ //}
+
+ a.javaBase.GenerateJavaBuildActions(ctx)
+
+ aaptPackageFlags := append([]string(nil), aaptFlags...)
+ var hasProduct bool
+ for _, f := range aaptPackageFlags {
+ if strings.HasPrefix(f, "--product") {
+ hasProduct = true
+ break
+ }
+ }
+
+ if !hasProduct {
+ aaptPackageFlags = append(aaptPackageFlags,
+ "--product "+ctx.AConfig().ProductAaptCharacteristics())
+ }
+
+ certificate := a.appProperties.Certificate
+ if certificate == "" {
+ certificate = ctx.AConfig().DefaultAppCertificate()
+ } else if dir, _ := filepath.Split(certificate); dir == "" {
+ certificate = filepath.Join(ctx.AConfig().DefaultAppCertificateDir(), certificate)
+ } else {
+ certificate = filepath.Join(ctx.AConfig().SrcDir(), certificate)
+ }
+
+ certificates := []string{certificate}
+ for _, c := range a.appProperties.Additional_certificates {
+ certificates = append(certificates, filepath.Join(ctx.AConfig().SrcDir(), c))
+ }
+
+ a.outputFile = CreateAppPackage(ctx, aaptPackageFlags, a.outputFile, certificates)
+ ctx.InstallFileName("app", ctx.ModuleName()+".apk", a.outputFile)
+}
+
+var aaptIgnoreFilenames = []string{
+ ".svn",
+ ".git",
+ ".ds_store",
+ "*.scc",
+ ".*",
+ "CVS",
+ "thumbs.db",
+ "picasa.ini",
+ "*~",
+}
+
+func (a *AndroidApp) aaptFlags(ctx common.AndroidModuleContext) ([]string, []string, bool) {
+ aaptFlags := a.appProperties.Aaptflags
+ hasVersionCode := false
+ hasVersionName := false
+ for _, f := range aaptFlags {
+ if strings.HasPrefix(f, "--version-code") {
+ hasVersionCode = true
+ } else if strings.HasPrefix(f, "--version-name") {
+ hasVersionName = true
+ }
+ }
+
+ if true /* is not a test */ {
+ aaptFlags = append(aaptFlags, "-z")
+ }
+
+ assetDirs := a.appProperties.Asset_dirs
+ if len(assetDirs) == 0 {
+ defaultAssetDir := filepath.Join(common.ModuleSrcDir(ctx), "assets")
+ if _, err := os.Stat(defaultAssetDir); err == nil {
+ assetDirs = []string{defaultAssetDir}
+ } else {
+ // Default asset directory doesn't exist, add a dep on the parent directory to
+ // regenerate the manifest if it is created later
+ // TODO: use glob to avoid rerunning whole regenerate if a different file is created?
+ ctx.AddNinjaFileDeps(common.ModuleSrcDir(ctx))
+ }
+ } else {
+ assetDirs = pathtools.PrefixPaths(assetDirs, common.ModuleSrcDir(ctx))
+ }
+
+ resourceDirs := a.appProperties.Android_resource_dirs
+ if len(resourceDirs) == 0 {
+ defaultResourceDir := filepath.Join(common.ModuleSrcDir(ctx), "res")
+ if _, err := os.Stat(defaultResourceDir); err == nil {
+ resourceDirs = []string{defaultResourceDir}
+ } else {
+ // Default resource directory doesn't exist, add a dep on the parent directory to
+ // regenerate the manifest if it is created later
+ // TODO: use glob to avoid rerunning whole regenerate if a different file is created?
+ ctx.AddNinjaFileDeps(common.ModuleSrcDir(ctx))
+ }
+ } else {
+ resourceDirs = pathtools.PrefixPaths(resourceDirs, common.ModuleSrcDir(ctx))
+ }
+
+ rootSrcDir := ctx.AConfig().SrcDir()
+ var overlayResourceDirs []string
+ // For every resource directory, check if there is an overlay directory with the same path.
+ // If found, it will be prepended to the list of resource directories.
+ for _, overlayDir := range ctx.AConfig().ResourceOverlays() {
+ for _, resourceDir := range resourceDirs {
+ relResourceDir, err := filepath.Rel(rootSrcDir, resourceDir)
+ if err != nil {
+ ctx.ModuleErrorf("resource directory %q is not in source tree", resourceDir)
+ continue
+ }
+ overlayResourceDir := filepath.Join(overlayDir, relResourceDir)
+ if _, err := os.Stat(overlayResourceDir); err == nil {
+ overlayResourceDirs = append(overlayResourceDirs, overlayResourceDir)
+ } else {
+ // Overlay resource directory doesn't exist, add a dep to regenerate the manifest if
+ // it is created later
+ ctx.AddNinjaFileDeps(overlayResourceDir)
+ }
+ }
+ }
+
+ if len(overlayResourceDirs) > 0 {
+ resourceDirs = append(overlayResourceDirs, resourceDirs...)
+ }
+
+ // aapt needs to rerun if any files are added or modified in the assets or resource directories,
+ // use glob to create a filelist.
+ var aaptDeps []string
+ var hasResources bool
+ for _, d := range resourceDirs {
+ newDeps := common.Glob(ctx, filepath.Join(d, "**/*"), aaptIgnoreFilenames)
+ aaptDeps = append(aaptDeps, newDeps...)
+ if len(newDeps) > 0 {
+ hasResources = true
+ }
+ }
+ for _, d := range assetDirs {
+ newDeps := common.Glob(ctx, filepath.Join(d, "**/*"), aaptIgnoreFilenames)
+ aaptDeps = append(aaptDeps, newDeps...)
+ }
+
+ manifestFile := a.properties.Manifest
+ if manifestFile == "" {
+ manifestFile = "AndroidManifest.xml"
+ }
+
+ manifestFile = filepath.Join(common.ModuleSrcDir(ctx), manifestFile)
+ aaptDeps = append(aaptDeps, manifestFile)
+
+ aaptFlags = append(aaptFlags, "-M "+manifestFile)
+ aaptFlags = append(aaptFlags, common.JoinWithPrefix(assetDirs, "-A "))
+ aaptFlags = append(aaptFlags, common.JoinWithPrefix(resourceDirs, "-S "))
+
+ ctx.VisitDirectDeps(func(module blueprint.Module) {
+ var depFile string
+ if sdkDep, ok := module.(sdkDependency); ok {
+ depFile = sdkDep.ClasspathFile()
+ } else if javaDep, ok := module.(JavaDependency); ok {
+ if ctx.OtherModuleName(module) == "framework-res" {
+ depFile = javaDep.(*javaBase).module.(*AndroidApp).exportPackage
+ }
+ }
+ if depFile != "" {
+ aaptFlags = append(aaptFlags, "-I "+depFile)
+ aaptDeps = append(aaptDeps, depFile)
+ }
+ })
+
+ sdkVersion := a.properties.Sdk_version
+ if sdkVersion == "" {
+ sdkVersion = ctx.AConfig().PlatformSdkVersion()
+ }
+
+ aaptFlags = append(aaptFlags, "--min-sdk-version "+sdkVersion)
+ aaptFlags = append(aaptFlags, "--target-sdk-version "+sdkVersion)
+
+ if !hasVersionCode {
+ aaptFlags = append(aaptFlags, "--version-code "+ctx.AConfig().PlatformSdkVersion())
+ }
+
+ if !hasVersionName {
+ aaptFlags = append(aaptFlags,
+ "--version-name "+ctx.AConfig().PlatformVersion()+"-"+ctx.AConfig().BuildNumber())
+ }
+
+ // TODO: LOCAL_PACKAGE_OVERRIDES
+ // $(addprefix --rename-manifest-package , $(PRIVATE_MANIFEST_PACKAGE_NAME)) \
+
+ // TODO: LOCAL_INSTRUMENTATION_FOR
+ // $(addprefix --rename-instrumentation-target-package , $(PRIVATE_MANIFEST_INSTRUMENTATION_FOR))
+
+ return aaptFlags, aaptDeps, hasResources
+}
+
+func AndroidAppFactory() (blueprint.Module, []interface{}) {
+ module := &AndroidApp{}
+
+ module.properties.Dex = true
+
+ return NewJavaBase(&module.javaBase, module, common.DeviceSupported, &module.appProperties)
+}
diff --git a/java/app_builder.go b/java/app_builder.go
new file mode 100644
index 00000000..69c6fe1d
--- /dev/null
+++ b/java/app_builder.go
@@ -0,0 +1,172 @@
+// Copyright 2015 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
+
+// This file generates the final rules for compiling all Java. All properties related to
+// compiling should have been translated into javaBuilderFlags or another argument to the Transform*
+// functions.
+
+import (
+ "path/filepath"
+ "strings"
+
+ "github.com/google/blueprint"
+
+ "android/soong/common"
+)
+
+var (
+ aaptCreateResourceJavaFile = pctx.StaticRule("aaptCreateResourceJavaFile",
+ blueprint.RuleParams{
+ Command: `rm -rf "$javaDir" && mkdir -p "$javaDir" && ` +
+ `$aaptCmd package -m $aaptFlags -P $publicResourcesFile -G $proguardOptionsFile ` +
+ `-J $javaDir || ( rm -rf "$javaDir/*"; exit 41 ) && ` +
+ `find $javaDir -name "*.java" > $javaFileList`,
+ Description: "aapt create R.java $out",
+ },
+ "aaptFlags", "publicResourcesFile", "proguardOptionsFile", "javaDir", "javaFileList")
+
+ aaptCreateAssetsPackage = pctx.StaticRule("aaptCreateAssetsPackage",
+ blueprint.RuleParams{
+ Command: `$aaptCmd package $aaptFlags -F $out`,
+ Description: "aapt export package $out",
+ },
+ "aaptFlags", "publicResourcesFile", "proguardOptionsFile", "javaDir", "javaFileList")
+
+ aaptAddResources = pctx.StaticRule("aaptAddResources",
+ blueprint.RuleParams{
+ // TODO: add-jni-shared-libs-to-package
+ Command: `cp -f $in $out.tmp && $aaptCmd package -u $aaptFlags -F $out.tmp && mv $out.tmp $out`,
+ Description: "aapt package $out",
+ },
+ "aaptFlags")
+
+ zipalign = pctx.StaticRule("zipalign",
+ blueprint.RuleParams{
+ Command: `$zipalignCmd -f $zipalignFlags 4 $in $out`,
+ Description: "zipalign $out",
+ },
+ "zipalignFlags")
+
+ signapk = pctx.StaticRule("signapk",
+ blueprint.RuleParams{
+ Command: `java -jar $signapkCmd $certificates $in $out`,
+ Description: "signapk $out",
+ },
+ "certificates")
+
+ androidManifestMerger = pctx.StaticRule("androidManifestMerger",
+ blueprint.RuleParams{
+ Command: "java -classpath $androidManifestMergerCmd com.android.manifmerger.Main merge " +
+ "--main $in --libs $libsManifests --out $out",
+ Description: "merge manifest files $out",
+ },
+ "libsManifests")
+)
+
+func init() {
+ pctx.StaticVariable("androidManifestMergerCmd", "${srcDir}/prebuilts/devtools/tools/lib/manifest-merger.jar")
+ pctx.VariableFunc("aaptCmd", func(c interface{}) (string, error) {
+ return c.(common.Config).HostBinTool("aapt")
+ })
+ pctx.VariableFunc("zipalignCmd", func(c interface{}) (string, error) {
+ return c.(common.Config).HostBinTool("zipalign")
+ })
+ pctx.VariableFunc("signapkCmd", func(c interface{}) (string, error) {
+ return c.(common.Config).HostJavaTool("signapk.jar")
+ })
+}
+
+func CreateResourceJavaFiles(ctx common.AndroidModuleContext, flags []string,
+ deps []string) (string, string, string) {
+ javaDir := filepath.Join(common.ModuleGenDir(ctx), "R")
+ javaFileList := filepath.Join(common.ModuleOutDir(ctx), "R.filelist")
+ publicResourcesFile := filepath.Join(common.ModuleOutDir(ctx), "public_resources.xml")
+ proguardOptionsFile := filepath.Join(common.ModuleOutDir(ctx), "proguard.options")
+
+ ctx.Build(pctx, blueprint.BuildParams{
+ Rule: aaptCreateResourceJavaFile,
+ Outputs: []string{publicResourcesFile, proguardOptionsFile, javaFileList},
+ Implicits: deps,
+ Args: map[string]string{
+ "aaptFlags": strings.Join(flags, " "),
+ "publicResourcesFile": publicResourcesFile,
+ "proguardOptionsFile": proguardOptionsFile,
+ "javaDir": javaDir,
+ "javaFileList": javaFileList,
+ },
+ })
+
+ return publicResourcesFile, proguardOptionsFile, javaFileList
+}
+
+func CreateExportPackage(ctx common.AndroidModuleContext, flags []string, deps []string) string {
+ outputFile := filepath.Join(common.ModuleOutDir(ctx), "package-export.apk")
+
+ ctx.Build(pctx, blueprint.BuildParams{
+ Rule: aaptCreateAssetsPackage,
+ Outputs: []string{outputFile},
+ Implicits: deps,
+ Args: map[string]string{
+ "aaptFlags": strings.Join(flags, " "),
+ },
+ })
+
+ return outputFile
+}
+
+func CreateAppPackage(ctx common.AndroidModuleContext, flags []string, jarFile string,
+ certificates []string) string {
+
+ resourceApk := filepath.Join(common.ModuleOutDir(ctx), "resources.apk")
+
+ ctx.Build(pctx, blueprint.BuildParams{
+ Rule: aaptAddResources,
+ Outputs: []string{resourceApk},
+ Inputs: []string{jarFile},
+ Args: map[string]string{
+ "aaptFlags": strings.Join(flags, " "),
+ },
+ })
+
+ signedApk := filepath.Join(common.ModuleOutDir(ctx), "signed.apk")
+
+ var certificateArgs []string
+ for _, c := range certificates {
+ certificateArgs = append(certificateArgs, c+".x509.pem", c+".pk8")
+ }
+
+ ctx.Build(pctx, blueprint.BuildParams{
+ Rule: signapk,
+ Outputs: []string{signedApk},
+ Inputs: []string{resourceApk},
+ Args: map[string]string{
+ "certificates": strings.Join(certificateArgs, " "),
+ },
+ })
+
+ outputFile := filepath.Join(common.ModuleOutDir(ctx), "package.apk")
+
+ ctx.Build(pctx, blueprint.BuildParams{
+ Rule: zipalign,
+ Outputs: []string{outputFile},
+ Inputs: []string{signedApk},
+ Args: map[string]string{
+ "zipalignFlags": "",
+ },
+ })
+
+ return outputFile
+}