blob: b66eb4b7dbcde83a0e99e38e9b3b4743b1e832cc [file] [log] [blame]
Colin Cross30e076a2015-04-13 13:58:27 -07001// Copyright 2015 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package java
16
17// This file contains the module types for compiling Android apps.
18
19import (
Colin Cross30e076a2015-04-13 13:58:27 -070020 "path/filepath"
21 "strings"
22
Colin Cross76b5f0c2017-08-29 16:02:06 -070023 "github.com/google/blueprint/proptools"
Colin Cross30e076a2015-04-13 13:58:27 -070024
Colin Cross635c3b02016-05-18 15:37:25 -070025 "android/soong/android"
Colin Cross30e076a2015-04-13 13:58:27 -070026)
27
Colin Cross3bc7ffa2017-11-22 16:19:37 -080028func init() {
29 android.RegisterPreSingletonType("overlay", OverlaySingletonFactory)
Colin Cross5ab4e6d2017-11-22 16:20:45 -080030 android.RegisterModuleType("android_app", AndroidAppFactory)
Colin Cross3bc7ffa2017-11-22 16:19:37 -080031}
32
Colin Cross30e076a2015-04-13 13:58:27 -070033// AAR prebuilts
34// AndroidManifest.xml merging
35// package splits
36
Colin Cross7d5136f2015-05-11 13:39:40 -070037type androidAppProperties struct {
38 // path to a certificate, or the name of a certificate in the default
39 // certificate directory, or blank to use the default product certificate
Nan Zhangea568a42017-11-08 21:20:04 -080040 Certificate *string
Colin Cross7d5136f2015-05-11 13:39:40 -070041
42 // paths to extra certificates to sign the apk with
43 Additional_certificates []string
44
45 // If set, create package-export.apk, which other packages can
46 // use to get PRODUCT-agnostic resource data like IDs and type definitions.
Nan Zhangea568a42017-11-08 21:20:04 -080047 Export_package_resources *bool
Colin Cross7d5136f2015-05-11 13:39:40 -070048
49 // flags passed to aapt when creating the apk
50 Aaptflags []string
51
52 // list of resource labels to generate individual resource packages
53 Package_splits []string
54
55 // list of directories relative to the Blueprints file containing assets.
56 // Defaults to "assets"
57 Asset_dirs []string
58
59 // list of directories relative to the Blueprints file containing
Colin Cross86a63ff2017-09-27 17:33:10 -070060 // Android resources
61 Resource_dirs []string
Colin Crosscb933592017-11-22 13:49:43 -080062
63 Instrumentation_for *string
Colin Cross7d5136f2015-05-11 13:39:40 -070064}
65
Colin Cross30e076a2015-04-13 13:58:27 -070066type AndroidApp struct {
Colin Cross46c9b8b2017-06-22 16:51:17 -070067 Module
Colin Cross30e076a2015-04-13 13:58:27 -070068
Colin Cross7d5136f2015-05-11 13:39:40 -070069 appProperties androidAppProperties
Colin Cross30e076a2015-04-13 13:58:27 -070070
Colin Cross3bc7ffa2017-11-22 16:19:37 -080071 aaptSrcJar android.Path
72 exportPackage android.Path
Colin Cross30e076a2015-04-13 13:58:27 -070073}
74
Colin Cross46c9b8b2017-06-22 16:51:17 -070075func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) {
76 a.Module.deps(ctx)
Colin Cross30e076a2015-04-13 13:58:27 -070077
Colin Cross3bc7ffa2017-11-22 16:19:37 -080078 if !Bool(a.properties.No_framework_libs) && !Bool(a.properties.No_standard_libs) {
Nan Zhangea568a42017-11-08 21:20:04 -080079 switch String(a.deviceProperties.Sdk_version) { // TODO: Res_sdk_version?
Colin Cross5ab4e6d2017-11-22 16:20:45 -080080 case "current", "system_current", "test_current", "":
Colin Crossbe1da472017-07-07 15:59:46 -070081 ctx.AddDependency(ctx.Module(), frameworkResTag, "framework-res")
Colin Cross30e076a2015-04-13 13:58:27 -070082 default:
83 // We'll already have a dependency on an sdk prebuilt android.jar
84 }
85 }
Colin Cross30e076a2015-04-13 13:58:27 -070086}
87
Colin Cross46c9b8b2017-06-22 16:51:17 -070088func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Colin Cross3bc7ffa2017-11-22 16:19:37 -080089 linkFlags, linkDeps, resDirs, overlayDirs := a.aapt2Flags(ctx)
Colin Cross30e076a2015-04-13 13:58:27 -070090
Colin Cross3bc7ffa2017-11-22 16:19:37 -080091 packageRes := android.PathForModuleOut(ctx, "package-res.apk")
92 srcJar := android.PathForModuleGen(ctx, "R.jar")
93 proguardOptionsFile := android.PathForModuleGen(ctx, "proguard.options")
Colin Cross30e076a2015-04-13 13:58:27 -070094
Colin Cross3bc7ffa2017-11-22 16:19:37 -080095 var compiledRes, compiledOverlay android.Paths
96 for _, dir := range resDirs {
97 compiledRes = append(compiledRes, aapt2Compile(ctx, dir.dir, dir.files).Paths()...)
Colin Cross30e076a2015-04-13 13:58:27 -070098 }
Colin Cross3bc7ffa2017-11-22 16:19:37 -080099 for _, dir := range overlayDirs {
100 compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir.dir, dir.files).Paths()...)
101 }
102
103 aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile,
104 linkFlags, linkDeps, compiledRes, compiledOverlay)
105
106 a.exportPackage = packageRes
107 a.aaptSrcJar = srcJar
108
109 ctx.CheckbuildFile(proguardOptionsFile)
110 ctx.CheckbuildFile(a.exportPackage)
111 ctx.CheckbuildFile(a.aaptSrcJar)
Colin Cross30e076a2015-04-13 13:58:27 -0700112
Colin Cross46c9b8b2017-06-22 16:51:17 -0700113 // apps manifests are handled by aapt, don't let Module see them
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700114 a.properties.Manifest = nil
Colin Cross30e076a2015-04-13 13:58:27 -0700115
116 //if !ctx.ContainsProperty("proguard.enabled") {
117 // a.properties.Proguard.Enabled = true
118 //}
119
Colin Cross5ab4e6d2017-11-22 16:20:45 -0800120 if String(a.appProperties.Instrumentation_for) == "" {
121 a.properties.Instrument = true
122 }
123
124 if ctx.ModuleName() != "framework-res" {
125 a.Module.compile(ctx, a.aaptSrcJar)
126 }
Colin Cross30e076a2015-04-13 13:58:27 -0700127
Nan Zhangea568a42017-11-08 21:20:04 -0800128 certificate := String(a.appProperties.Certificate)
Colin Cross30e076a2015-04-13 13:58:27 -0700129 if certificate == "" {
Colin Cross6510f912017-11-29 00:27:14 -0800130 certificate = ctx.Config().DefaultAppCertificate(ctx).String()
Colin Cross30e076a2015-04-13 13:58:27 -0700131 } else if dir, _ := filepath.Split(certificate); dir == "" {
Colin Cross6510f912017-11-29 00:27:14 -0800132 certificate = filepath.Join(ctx.Config().DefaultAppCertificateDir(ctx).String(), certificate)
Colin Cross30e076a2015-04-13 13:58:27 -0700133 } else {
Colin Cross635c3b02016-05-18 15:37:25 -0700134 certificate = filepath.Join(android.PathForSource(ctx).String(), certificate)
Colin Cross30e076a2015-04-13 13:58:27 -0700135 }
136
137 certificates := []string{certificate}
138 for _, c := range a.appProperties.Additional_certificates {
Colin Cross635c3b02016-05-18 15:37:25 -0700139 certificates = append(certificates, filepath.Join(android.PathForSource(ctx).String(), c))
Colin Cross30e076a2015-04-13 13:58:27 -0700140 }
141
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800142 packageFile := android.PathForModuleOut(ctx, "package.apk")
143
144 CreateAppPackage(ctx, packageFile, a.exportPackage, a.outputFile, certificates)
145
146 a.outputFile = packageFile
147
Colin Cross5ab4e6d2017-11-22 16:20:45 -0800148 if ctx.ModuleName() == "framework-res" {
149 // framework-res.apk is installed as system/framework/framework-res.apk
150 ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"), ctx.ModuleName()+".apk", a.outputFile)
151 } else {
152 ctx.InstallFile(android.PathForModuleInstall(ctx, "app"), ctx.ModuleName()+".apk", a.outputFile)
153 }
Colin Cross30e076a2015-04-13 13:58:27 -0700154}
155
156var aaptIgnoreFilenames = []string{
157 ".svn",
158 ".git",
159 ".ds_store",
160 "*.scc",
161 ".*",
162 "CVS",
163 "thumbs.db",
164 "picasa.ini",
165 "*~",
166}
167
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800168type globbedResourceDir struct {
169 dir android.Path
170 files android.Paths
171}
172
173func (a *AndroidApp) aapt2Flags(ctx android.ModuleContext) (flags []string, deps android.Paths,
174 resDirs, overlayDirs []globbedResourceDir) {
175
Colin Cross30e076a2015-04-13 13:58:27 -0700176 hasVersionCode := false
177 hasVersionName := false
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800178 hasProduct := false
179 for _, f := range a.appProperties.Aaptflags {
Colin Cross30e076a2015-04-13 13:58:27 -0700180 if strings.HasPrefix(f, "--version-code") {
181 hasVersionCode = true
182 } else if strings.HasPrefix(f, "--version-name") {
183 hasVersionName = true
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800184 } else if strings.HasPrefix(f, "--product") {
185 hasProduct = true
Colin Cross30e076a2015-04-13 13:58:27 -0700186 }
187 }
188
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800189 var linkFlags []string
Colin Cross30e076a2015-04-13 13:58:27 -0700190
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800191 // Flags specified in Android.bp
192 linkFlags = append(linkFlags, a.appProperties.Aaptflags...)
193
194 linkFlags = append(linkFlags, "--no-static-lib-packages")
195
196 // Find implicit or explicit asset and resource dirs
Colin Cross635c3b02016-05-18 15:37:25 -0700197 assetDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.appProperties.Asset_dirs, "assets")
Colin Cross86a63ff2017-09-27 17:33:10 -0700198 resourceDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.appProperties.Resource_dirs, "res")
Colin Cross30e076a2015-04-13 13:58:27 -0700199
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800200 var linkDeps android.Paths
201
202 // Glob directories into lists of paths
203 for _, dir := range resourceDirs {
204 resDirs = append(resDirs, globbedResourceDir{
205 dir: dir,
206 files: resourceGlob(ctx, dir),
207 })
208 overlayDirs = append(overlayDirs, overlayResourceGlob(ctx, dir)...)
Colin Cross30e076a2015-04-13 13:58:27 -0700209 }
210
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800211 var assetFiles android.Paths
212 for _, dir := range assetDirs {
213 assetFiles = append(assetFiles, resourceGlob(ctx, dir)...)
Colin Cross30e076a2015-04-13 13:58:27 -0700214 }
215
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800216 // App manifest file
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700217 var manifestFile string
218 if a.properties.Manifest == nil {
Colin Cross30e076a2015-04-13 13:58:27 -0700219 manifestFile = "AndroidManifest.xml"
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700220 } else {
221 manifestFile = *a.properties.Manifest
Colin Cross30e076a2015-04-13 13:58:27 -0700222 }
223
Colin Cross635c3b02016-05-18 15:37:25 -0700224 manifestPath := android.PathForModuleSrc(ctx, manifestFile)
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800225 linkFlags = append(linkFlags, "--manifest "+manifestPath.String())
226 linkDeps = append(linkDeps, manifestPath)
Colin Cross30e076a2015-04-13 13:58:27 -0700227
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800228 linkFlags = append(linkFlags, android.JoinWithPrefix(assetDirs.Strings(), "-A "))
229 linkDeps = append(linkDeps, assetFiles...)
Colin Cross30e076a2015-04-13 13:58:27 -0700230
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800231 // Include dirs
Colin Crossd11fcda2017-10-23 17:59:01 -0700232 ctx.VisitDirectDeps(func(module android.Module) {
Colin Cross74d73e22017-08-02 11:05:49 -0700233 var depFiles android.Paths
Colin Crossfc3674a2017-09-18 17:41:52 -0700234 if javaDep, ok := module.(Dependency); ok {
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800235 // TODO: shared android libraries
Colin Cross30e076a2015-04-13 13:58:27 -0700236 if ctx.OtherModuleName(module) == "framework-res" {
Colin Cross74d73e22017-08-02 11:05:49 -0700237 depFiles = android.Paths{javaDep.(*AndroidApp).exportPackage}
Colin Cross30e076a2015-04-13 13:58:27 -0700238 }
239 }
Colin Cross74d73e22017-08-02 11:05:49 -0700240
241 for _, dep := range depFiles {
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800242 linkFlags = append(linkFlags, "-I "+dep.String())
Colin Cross30e076a2015-04-13 13:58:27 -0700243 }
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800244 linkDeps = append(linkDeps, depFiles...)
Colin Cross30e076a2015-04-13 13:58:27 -0700245 })
246
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800247 // SDK version flags
Nan Zhangea568a42017-11-08 21:20:04 -0800248 sdkVersion := String(a.deviceProperties.Sdk_version)
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800249 switch sdkVersion {
250 case "", "current", "system_current", "test_current":
Colin Cross6510f912017-11-29 00:27:14 -0800251 sdkVersion = ctx.Config().AppsDefaultVersionName()
Colin Cross30e076a2015-04-13 13:58:27 -0700252 }
253
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800254 linkFlags = append(linkFlags, "--min-sdk-version "+sdkVersion)
255 linkFlags = append(linkFlags, "--target-sdk-version "+sdkVersion)
Colin Cross30e076a2015-04-13 13:58:27 -0700256
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800257 // Product characteristics
Colin Cross6510f912017-11-29 00:27:14 -0800258 if !hasProduct && len(ctx.Config().ProductAAPTCharacteristics()) > 0 {
259 linkFlags = append(linkFlags, "--product", ctx.Config().ProductAAPTCharacteristics())
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800260 }
261
262 // Product AAPT config
Colin Cross6510f912017-11-29 00:27:14 -0800263 for _, aaptConfig := range ctx.Config().ProductAAPTConfig() {
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800264 linkFlags = append(linkFlags, "-c", aaptConfig)
265 }
266
267 // Product AAPT preferred config
Colin Cross6510f912017-11-29 00:27:14 -0800268 if len(ctx.Config().ProductAAPTPreferredConfig()) > 0 {
269 linkFlags = append(linkFlags, "--preferred-density", ctx.Config().ProductAAPTPreferredConfig())
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800270 }
271
272 // Version code
Colin Cross30e076a2015-04-13 13:58:27 -0700273 if !hasVersionCode {
Colin Cross6510f912017-11-29 00:27:14 -0800274 linkFlags = append(linkFlags, "--version-code", ctx.Config().PlatformSdkVersion())
Colin Cross30e076a2015-04-13 13:58:27 -0700275 }
276
277 if !hasVersionName {
Colin Cross6510f912017-11-29 00:27:14 -0800278 versionName := proptools.NinjaEscape([]string{ctx.Config().AppsDefaultVersionName()})[0]
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800279 linkFlags = append(linkFlags, "--version-name ", versionName)
280 }
281
282 if String(a.appProperties.Instrumentation_for) != "" {
283 linkFlags = append(linkFlags,
284 "--rename-instrumentation-target-package",
285 String(a.appProperties.Instrumentation_for))
Colin Cross30e076a2015-04-13 13:58:27 -0700286 }
287
288 // TODO: LOCAL_PACKAGE_OVERRIDES
289 // $(addprefix --rename-manifest-package , $(PRIVATE_MANIFEST_PACKAGE_NAME)) \
290
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800291 return linkFlags, linkDeps, resDirs, overlayDirs
Colin Cross30e076a2015-04-13 13:58:27 -0700292}
293
Colin Cross36242852017-06-23 15:06:31 -0700294func AndroidAppFactory() android.Module {
Colin Cross30e076a2015-04-13 13:58:27 -0700295 module := &AndroidApp{}
296
Colin Cross36242852017-06-23 15:06:31 -0700297 module.AddProperties(
Colin Cross540eff82017-06-22 17:01:52 -0700298 &module.Module.properties,
299 &module.Module.deviceProperties,
300 &module.appProperties)
Colin Cross36242852017-06-23 15:06:31 -0700301
302 android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
303 return module
Colin Cross30e076a2015-04-13 13:58:27 -0700304}
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800305
306func resourceGlob(ctx android.ModuleContext, dir android.Path) android.Paths {
307 var ret android.Paths
308 files := ctx.Glob(filepath.Join(dir.String(), "**/*"), aaptIgnoreFilenames)
309 for _, f := range files {
310 if isDir, err := ctx.Fs().IsDir(f.String()); err != nil {
311 ctx.ModuleErrorf("error in IsDir(%s): %s", f.String(), err.Error())
312 return nil
313 } else if !isDir {
314 ret = append(ret, f)
315 }
316 }
317 return ret
318}
319
320type overlayGlobResult struct {
321 dir string
322 paths android.DirectorySortedPaths
323}
324
325const overlayDataKey = "overlayDataKey"
326
327func overlayResourceGlob(ctx android.ModuleContext, dir android.Path) []globbedResourceDir {
Colin Cross6510f912017-11-29 00:27:14 -0800328 overlayData := ctx.Config().Get(overlayDataKey).([]overlayGlobResult)
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800329
330 var ret []globbedResourceDir
331
332 for _, data := range overlayData {
333 files := data.paths.PathsInDirectory(filepath.Join(data.dir, dir.String()))
334 if len(files) > 0 {
335 ret = append(ret, globbedResourceDir{
336 dir: android.PathForSource(ctx, data.dir, dir.String()),
337 files: files,
338 })
339 }
340 }
341
342 return ret
343}
344
345func OverlaySingletonFactory() android.Singleton {
346 return overlaySingleton{}
347}
348
349type overlaySingleton struct{}
350
351func (overlaySingleton) GenerateBuildActions(ctx android.SingletonContext) {
352 var overlayData []overlayGlobResult
Colin Crossaabf6792017-11-29 00:27:14 -0800353 for _, overlay := range ctx.Config().ResourceOverlays() {
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800354 var result overlayGlobResult
355 result.dir = overlay
356 files, err := ctx.GlobWithDeps(filepath.Join(overlay, "**/*"), aaptIgnoreFilenames)
357 if err != nil {
358 ctx.Errorf("failed to glob resource dir %q: %s", overlay, err.Error())
359 continue
360 }
361 var paths android.Paths
362 for _, f := range files {
363 if isDir, err := ctx.Fs().IsDir(f); err != nil {
364 ctx.Errorf("error in IsDir(%s): %s", f, err.Error())
365 return
366 } else if !isDir {
367 paths = append(paths, android.PathForSource(ctx, f))
368 }
369 }
370 result.paths = android.PathsToDirectorySortedPaths(paths)
371 overlayData = append(overlayData, result)
372 }
373
Colin Crossaabf6792017-11-29 00:27:14 -0800374 ctx.Config().Once(overlayDataKey, func() interface{} {
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800375 return overlayData
376 })
377}