2015-04-13 22:58:27 +02:00
|
|
|
// 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 (
|
|
|
|
"path/filepath"
|
|
|
|
"strings"
|
|
|
|
|
2017-08-30 01:02:06 +02:00
|
|
|
"github.com/google/blueprint/proptools"
|
2015-04-13 22:58:27 +02:00
|
|
|
|
2016-05-19 00:37:25 +02:00
|
|
|
"android/soong/android"
|
2015-04-13 22:58:27 +02:00
|
|
|
)
|
|
|
|
|
2017-11-23 01:19:37 +01:00
|
|
|
func init() {
|
|
|
|
android.RegisterPreSingletonType("overlay", OverlaySingletonFactory)
|
|
|
|
}
|
|
|
|
|
2015-04-13 22:58:27 +02:00
|
|
|
// AAR prebuilts
|
|
|
|
// AndroidManifest.xml merging
|
|
|
|
// package splits
|
|
|
|
|
2015-05-11 22:39:40 +02:00
|
|
|
type androidAppProperties struct {
|
|
|
|
// path to a certificate, or the name of a certificate in the default
|
|
|
|
// certificate directory, or blank to use the default product certificate
|
2017-11-09 06:20:04 +01:00
|
|
|
Certificate *string
|
2015-04-13 22:58:27 +02:00
|
|
|
|
2015-05-11 22:39:40 +02:00
|
|
|
// paths to extra certificates to sign the apk with
|
|
|
|
Additional_certificates []string
|
2015-04-13 22:58:27 +02:00
|
|
|
|
2015-05-11 22:39:40 +02:00
|
|
|
// If set, create package-export.apk, which other packages can
|
|
|
|
// use to get PRODUCT-agnostic resource data like IDs and type definitions.
|
2017-11-09 06:20:04 +01:00
|
|
|
Export_package_resources *bool
|
2015-04-13 22:58:27 +02:00
|
|
|
|
2015-05-11 22:39:40 +02:00
|
|
|
// flags passed to aapt when creating the apk
|
|
|
|
Aaptflags []string
|
2015-04-13 22:58:27 +02:00
|
|
|
|
2015-05-11 22:39:40 +02:00
|
|
|
// list of resource labels to generate individual resource packages
|
|
|
|
Package_splits []string
|
2015-04-13 22:58:27 +02:00
|
|
|
|
2015-05-11 22:39:40 +02:00
|
|
|
// list of directories relative to the Blueprints file containing assets.
|
|
|
|
// Defaults to "assets"
|
|
|
|
Asset_dirs []string
|
2015-04-13 22:58:27 +02:00
|
|
|
|
2015-05-11 22:39:40 +02:00
|
|
|
// list of directories relative to the Blueprints file containing
|
2017-09-28 02:33:10 +02:00
|
|
|
// Android resources
|
|
|
|
Resource_dirs []string
|
2017-11-22 22:49:43 +01:00
|
|
|
|
|
|
|
Instrumentation_for *string
|
2015-05-11 22:39:40 +02:00
|
|
|
}
|
2015-04-13 22:58:27 +02:00
|
|
|
|
2015-05-11 22:39:40 +02:00
|
|
|
type AndroidApp struct {
|
2017-06-23 01:51:17 +02:00
|
|
|
Module
|
2015-05-11 22:39:40 +02:00
|
|
|
|
|
|
|
appProperties androidAppProperties
|
2015-04-13 22:58:27 +02:00
|
|
|
|
2017-11-23 01:19:37 +01:00
|
|
|
aaptSrcJar android.Path
|
|
|
|
exportPackage android.Path
|
2015-04-13 22:58:27 +02:00
|
|
|
}
|
|
|
|
|
2017-06-23 01:51:17 +02:00
|
|
|
func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) {
|
|
|
|
a.Module.deps(ctx)
|
2015-04-13 22:58:27 +02:00
|
|
|
|
2017-11-23 01:19:37 +01:00
|
|
|
if !Bool(a.properties.No_framework_libs) && !Bool(a.properties.No_standard_libs) {
|
2017-11-09 06:20:04 +01:00
|
|
|
switch String(a.deviceProperties.Sdk_version) { // TODO: Res_sdk_version?
|
2015-04-13 22:58:27 +02:00
|
|
|
case "current", "system_current", "":
|
2017-07-08 00:59:46 +02:00
|
|
|
ctx.AddDependency(ctx.Module(), frameworkResTag, "framework-res")
|
2015-04-13 22:58:27 +02:00
|
|
|
default:
|
|
|
|
// We'll already have a dependency on an sdk prebuilt android.jar
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-23 01:51:17 +02:00
|
|
|
func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
2017-11-23 01:19:37 +01:00
|
|
|
linkFlags, linkDeps, resDirs, overlayDirs := a.aapt2Flags(ctx)
|
2015-04-13 22:58:27 +02:00
|
|
|
|
2017-11-23 01:19:37 +01:00
|
|
|
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()...)
|
2015-04-13 22:58:27 +02:00
|
|
|
}
|
|
|
|
|
2017-11-23 01:19:37 +01:00
|
|
|
aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile,
|
|
|
|
linkFlags, linkDeps, compiledRes, compiledOverlay)
|
|
|
|
|
|
|
|
a.exportPackage = packageRes
|
|
|
|
a.aaptSrcJar = srcJar
|
|
|
|
|
|
|
|
ctx.CheckbuildFile(proguardOptionsFile)
|
|
|
|
ctx.CheckbuildFile(a.exportPackage)
|
|
|
|
ctx.CheckbuildFile(a.aaptSrcJar)
|
|
|
|
|
2017-06-23 01:51:17 +02:00
|
|
|
// apps manifests are handled by aapt, don't let Module see them
|
2015-09-24 00:26:20 +02:00
|
|
|
a.properties.Manifest = nil
|
2015-04-13 22:58:27 +02:00
|
|
|
|
|
|
|
//if !ctx.ContainsProperty("proguard.enabled") {
|
|
|
|
// a.properties.Proguard.Enabled = true
|
|
|
|
//}
|
|
|
|
|
2017-06-23 01:51:17 +02:00
|
|
|
a.Module.compile(ctx)
|
2015-04-13 22:58:27 +02:00
|
|
|
|
2017-11-09 06:20:04 +01:00
|
|
|
certificate := String(a.appProperties.Certificate)
|
2015-04-13 22:58:27 +02:00
|
|
|
if certificate == "" {
|
2017-11-29 09:27:14 +01:00
|
|
|
certificate = ctx.Config().DefaultAppCertificate(ctx).String()
|
2015-04-13 22:58:27 +02:00
|
|
|
} else if dir, _ := filepath.Split(certificate); dir == "" {
|
2017-11-29 09:27:14 +01:00
|
|
|
certificate = filepath.Join(ctx.Config().DefaultAppCertificateDir(ctx).String(), certificate)
|
2015-04-13 22:58:27 +02:00
|
|
|
} else {
|
2016-05-19 00:37:25 +02:00
|
|
|
certificate = filepath.Join(android.PathForSource(ctx).String(), certificate)
|
2015-04-13 22:58:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
certificates := []string{certificate}
|
|
|
|
for _, c := range a.appProperties.Additional_certificates {
|
2016-05-19 00:37:25 +02:00
|
|
|
certificates = append(certificates, filepath.Join(android.PathForSource(ctx).String(), c))
|
2015-04-13 22:58:27 +02:00
|
|
|
}
|
|
|
|
|
2017-11-23 01:19:37 +01:00
|
|
|
packageFile := android.PathForModuleOut(ctx, "package.apk")
|
|
|
|
|
|
|
|
CreateAppPackage(ctx, packageFile, a.exportPackage, a.outputFile, certificates)
|
|
|
|
|
|
|
|
a.outputFile = packageFile
|
|
|
|
|
2017-08-31 21:29:17 +02:00
|
|
|
ctx.InstallFile(android.PathForModuleInstall(ctx, "app"), ctx.ModuleName()+".apk", a.outputFile)
|
2015-04-13 22:58:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
var aaptIgnoreFilenames = []string{
|
|
|
|
".svn",
|
|
|
|
".git",
|
|
|
|
".ds_store",
|
|
|
|
"*.scc",
|
|
|
|
".*",
|
|
|
|
"CVS",
|
|
|
|
"thumbs.db",
|
|
|
|
"picasa.ini",
|
|
|
|
"*~",
|
|
|
|
}
|
|
|
|
|
2017-11-23 01:19:37 +01:00
|
|
|
type globbedResourceDir struct {
|
|
|
|
dir android.Path
|
|
|
|
files android.Paths
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *AndroidApp) aapt2Flags(ctx android.ModuleContext) (flags []string, deps android.Paths,
|
|
|
|
resDirs, overlayDirs []globbedResourceDir) {
|
|
|
|
|
2015-04-13 22:58:27 +02:00
|
|
|
hasVersionCode := false
|
|
|
|
hasVersionName := false
|
2017-11-23 01:19:37 +01:00
|
|
|
hasProduct := false
|
|
|
|
for _, f := range a.appProperties.Aaptflags {
|
2015-04-13 22:58:27 +02:00
|
|
|
if strings.HasPrefix(f, "--version-code") {
|
|
|
|
hasVersionCode = true
|
|
|
|
} else if strings.HasPrefix(f, "--version-name") {
|
|
|
|
hasVersionName = true
|
2017-11-23 01:19:37 +01:00
|
|
|
} else if strings.HasPrefix(f, "--product") {
|
|
|
|
hasProduct = true
|
2015-04-13 22:58:27 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-23 01:19:37 +01:00
|
|
|
var linkFlags []string
|
|
|
|
|
|
|
|
// Flags specified in Android.bp
|
|
|
|
linkFlags = append(linkFlags, a.appProperties.Aaptflags...)
|
2015-04-13 22:58:27 +02:00
|
|
|
|
2017-11-23 01:19:37 +01:00
|
|
|
linkFlags = append(linkFlags, "--no-static-lib-packages")
|
|
|
|
|
|
|
|
// Find implicit or explicit asset and resource dirs
|
2016-05-19 00:37:25 +02:00
|
|
|
assetDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.appProperties.Asset_dirs, "assets")
|
2017-09-28 02:33:10 +02:00
|
|
|
resourceDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.appProperties.Resource_dirs, "res")
|
2015-04-13 22:58:27 +02:00
|
|
|
|
2017-11-23 01:19:37 +01:00
|
|
|
var linkDeps android.Paths
|
2015-04-13 22:58:27 +02:00
|
|
|
|
2017-11-23 01:19:37 +01:00
|
|
|
// Glob directories into lists of paths
|
|
|
|
for _, dir := range resourceDirs {
|
|
|
|
resDirs = append(resDirs, globbedResourceDir{
|
|
|
|
dir: dir,
|
|
|
|
files: resourceGlob(ctx, dir),
|
|
|
|
})
|
|
|
|
overlayDirs = append(overlayDirs, overlayResourceGlob(ctx, dir)...)
|
2015-04-13 22:58:27 +02:00
|
|
|
}
|
|
|
|
|
2017-11-23 01:19:37 +01:00
|
|
|
var assetFiles android.Paths
|
|
|
|
for _, dir := range assetDirs {
|
|
|
|
assetFiles = append(assetFiles, resourceGlob(ctx, dir)...)
|
2015-04-13 22:58:27 +02:00
|
|
|
}
|
|
|
|
|
2017-11-23 01:19:37 +01:00
|
|
|
// App manifest file
|
2015-09-24 00:26:20 +02:00
|
|
|
var manifestFile string
|
|
|
|
if a.properties.Manifest == nil {
|
2015-04-13 22:58:27 +02:00
|
|
|
manifestFile = "AndroidManifest.xml"
|
2015-09-24 00:26:20 +02:00
|
|
|
} else {
|
|
|
|
manifestFile = *a.properties.Manifest
|
2015-04-13 22:58:27 +02:00
|
|
|
}
|
|
|
|
|
2016-05-19 00:37:25 +02:00
|
|
|
manifestPath := android.PathForModuleSrc(ctx, manifestFile)
|
2017-11-23 01:19:37 +01:00
|
|
|
linkFlags = append(linkFlags, "--manifest "+manifestPath.String())
|
|
|
|
linkDeps = append(linkDeps, manifestPath)
|
2015-04-13 22:58:27 +02:00
|
|
|
|
2017-11-23 01:19:37 +01:00
|
|
|
linkFlags = append(linkFlags, android.JoinWithPrefix(assetDirs.Strings(), "-A "))
|
|
|
|
linkDeps = append(linkDeps, assetFiles...)
|
2015-04-13 22:58:27 +02:00
|
|
|
|
2017-11-23 01:19:37 +01:00
|
|
|
// Include dirs
|
2017-10-24 02:59:01 +02:00
|
|
|
ctx.VisitDirectDeps(func(module android.Module) {
|
2017-08-02 20:05:49 +02:00
|
|
|
var depFiles android.Paths
|
2017-09-19 02:41:52 +02:00
|
|
|
if javaDep, ok := module.(Dependency); ok {
|
2017-11-23 01:19:37 +01:00
|
|
|
// TODO: shared android libraries
|
2015-04-13 22:58:27 +02:00
|
|
|
if ctx.OtherModuleName(module) == "framework-res" {
|
2017-08-02 20:05:49 +02:00
|
|
|
depFiles = android.Paths{javaDep.(*AndroidApp).exportPackage}
|
2015-04-13 22:58:27 +02:00
|
|
|
}
|
|
|
|
}
|
2017-08-02 20:05:49 +02:00
|
|
|
|
|
|
|
for _, dep := range depFiles {
|
2017-11-23 01:19:37 +01:00
|
|
|
linkFlags = append(linkFlags, "-I "+dep.String())
|
2015-04-13 22:58:27 +02:00
|
|
|
}
|
2017-11-23 01:19:37 +01:00
|
|
|
linkDeps = append(linkDeps, depFiles...)
|
2015-04-13 22:58:27 +02:00
|
|
|
})
|
|
|
|
|
2017-11-23 01:19:37 +01:00
|
|
|
// SDK version flags
|
2017-11-09 06:20:04 +01:00
|
|
|
sdkVersion := String(a.deviceProperties.Sdk_version)
|
2017-11-23 01:19:37 +01:00
|
|
|
switch sdkVersion {
|
|
|
|
case "", "current", "system_current", "test_current":
|
2017-11-29 09:27:14 +01:00
|
|
|
sdkVersion = ctx.Config().AppsDefaultVersionName()
|
2015-04-13 22:58:27 +02:00
|
|
|
}
|
|
|
|
|
2017-11-23 01:19:37 +01:00
|
|
|
linkFlags = append(linkFlags, "--min-sdk-version "+sdkVersion)
|
|
|
|
linkFlags = append(linkFlags, "--target-sdk-version "+sdkVersion)
|
2015-04-13 22:58:27 +02:00
|
|
|
|
2017-11-23 01:19:37 +01:00
|
|
|
// Product characteristics
|
2017-11-29 09:27:14 +01:00
|
|
|
if !hasProduct && len(ctx.Config().ProductAAPTCharacteristics()) > 0 {
|
|
|
|
linkFlags = append(linkFlags, "--product", ctx.Config().ProductAAPTCharacteristics())
|
2017-11-23 01:19:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Product AAPT config
|
2017-11-29 09:27:14 +01:00
|
|
|
for _, aaptConfig := range ctx.Config().ProductAAPTConfig() {
|
2017-11-23 01:19:37 +01:00
|
|
|
linkFlags = append(linkFlags, "-c", aaptConfig)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Product AAPT preferred config
|
2017-11-29 09:27:14 +01:00
|
|
|
if len(ctx.Config().ProductAAPTPreferredConfig()) > 0 {
|
|
|
|
linkFlags = append(linkFlags, "--preferred-density", ctx.Config().ProductAAPTPreferredConfig())
|
2017-11-23 01:19:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Version code
|
2015-04-13 22:58:27 +02:00
|
|
|
if !hasVersionCode {
|
2017-11-29 09:27:14 +01:00
|
|
|
linkFlags = append(linkFlags, "--version-code", ctx.Config().PlatformSdkVersion())
|
2015-04-13 22:58:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if !hasVersionName {
|
2017-11-29 09:27:14 +01:00
|
|
|
versionName := proptools.NinjaEscape([]string{ctx.Config().AppsDefaultVersionName()})[0]
|
2017-11-23 01:19:37 +01:00
|
|
|
linkFlags = append(linkFlags, "--version-name ", versionName)
|
|
|
|
}
|
|
|
|
|
|
|
|
if String(a.appProperties.Instrumentation_for) != "" {
|
|
|
|
linkFlags = append(linkFlags,
|
|
|
|
"--rename-instrumentation-target-package",
|
|
|
|
String(a.appProperties.Instrumentation_for))
|
2015-04-13 22:58:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: LOCAL_PACKAGE_OVERRIDES
|
|
|
|
// $(addprefix --rename-manifest-package , $(PRIVATE_MANIFEST_PACKAGE_NAME)) \
|
|
|
|
|
2017-11-23 01:19:37 +01:00
|
|
|
return linkFlags, linkDeps, resDirs, overlayDirs
|
2015-04-13 22:58:27 +02:00
|
|
|
}
|
|
|
|
|
2017-06-24 00:06:31 +02:00
|
|
|
func AndroidAppFactory() android.Module {
|
2015-04-13 22:58:27 +02:00
|
|
|
module := &AndroidApp{}
|
|
|
|
|
2017-06-24 00:06:31 +02:00
|
|
|
module.AddProperties(
|
2017-06-23 02:01:52 +02:00
|
|
|
&module.Module.properties,
|
|
|
|
&module.Module.deviceProperties,
|
|
|
|
&module.appProperties)
|
2017-06-24 00:06:31 +02:00
|
|
|
|
|
|
|
android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
|
|
|
|
return module
|
2015-04-13 22:58:27 +02:00
|
|
|
}
|
2017-11-23 01:19:37 +01:00
|
|
|
|
|
|
|
func resourceGlob(ctx android.ModuleContext, dir android.Path) android.Paths {
|
|
|
|
var ret android.Paths
|
|
|
|
files := ctx.Glob(filepath.Join(dir.String(), "**/*"), aaptIgnoreFilenames)
|
|
|
|
for _, f := range files {
|
|
|
|
if isDir, err := ctx.Fs().IsDir(f.String()); err != nil {
|
|
|
|
ctx.ModuleErrorf("error in IsDir(%s): %s", f.String(), err.Error())
|
|
|
|
return nil
|
|
|
|
} else if !isDir {
|
|
|
|
ret = append(ret, f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
|
|
|
type overlayGlobResult struct {
|
|
|
|
dir string
|
|
|
|
paths android.DirectorySortedPaths
|
|
|
|
}
|
|
|
|
|
|
|
|
const overlayDataKey = "overlayDataKey"
|
|
|
|
|
|
|
|
func overlayResourceGlob(ctx android.ModuleContext, dir android.Path) []globbedResourceDir {
|
2017-11-29 09:27:14 +01:00
|
|
|
overlayData := ctx.Config().Get(overlayDataKey).([]overlayGlobResult)
|
2017-11-23 01:19:37 +01:00
|
|
|
|
|
|
|
var ret []globbedResourceDir
|
|
|
|
|
|
|
|
for _, data := range overlayData {
|
|
|
|
files := data.paths.PathsInDirectory(filepath.Join(data.dir, dir.String()))
|
|
|
|
if len(files) > 0 {
|
|
|
|
ret = append(ret, globbedResourceDir{
|
|
|
|
dir: android.PathForSource(ctx, data.dir, dir.String()),
|
|
|
|
files: files,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
|
|
|
func OverlaySingletonFactory() android.Singleton {
|
|
|
|
return overlaySingleton{}
|
|
|
|
}
|
|
|
|
|
|
|
|
type overlaySingleton struct{}
|
|
|
|
|
|
|
|
func (overlaySingleton) GenerateBuildActions(ctx android.SingletonContext) {
|
|
|
|
var overlayData []overlayGlobResult
|
2017-11-29 09:27:14 +01:00
|
|
|
for _, overlay := range ctx.Config().ResourceOverlays() {
|
2017-11-23 01:19:37 +01:00
|
|
|
var result overlayGlobResult
|
|
|
|
result.dir = 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 isDir, err := ctx.Fs().IsDir(f); err != nil {
|
|
|
|
ctx.Errorf("error in IsDir(%s): %s", f, err.Error())
|
|
|
|
return
|
|
|
|
} else if !isDir {
|
|
|
|
paths = append(paths, android.PathForSource(ctx, f))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
result.paths = android.PathsToDirectorySortedPaths(paths)
|
|
|
|
overlayData = append(overlayData, result)
|
|
|
|
}
|
|
|
|
|
2017-11-29 09:27:14 +01:00
|
|
|
ctx.Config().Once(overlayDataKey, func() interface{} {
|
2017-11-23 01:19:37 +01:00
|
|
|
return overlayData
|
|
|
|
})
|
|
|
|
}
|