blob: fd1fe33ff491769a7a6843f5018d165cdb6daa98 [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)
30}
31
Colin Cross30e076a2015-04-13 13:58:27 -070032// AAR prebuilts
33// AndroidManifest.xml merging
34// package splits
35
Colin Cross7d5136f2015-05-11 13:39:40 -070036type androidAppProperties struct {
37 // path to a certificate, or the name of a certificate in the default
38 // certificate directory, or blank to use the default product certificate
Nan Zhangea568a42017-11-08 21:20:04 -080039 Certificate *string
Colin Cross7d5136f2015-05-11 13:39:40 -070040
41 // paths to extra certificates to sign the apk with
42 Additional_certificates []string
43
44 // If set, create package-export.apk, which other packages can
45 // use to get PRODUCT-agnostic resource data like IDs and type definitions.
Nan Zhangea568a42017-11-08 21:20:04 -080046 Export_package_resources *bool
Colin Cross7d5136f2015-05-11 13:39:40 -070047
48 // flags passed to aapt when creating the apk
49 Aaptflags []string
50
51 // list of resource labels to generate individual resource packages
52 Package_splits []string
53
54 // list of directories relative to the Blueprints file containing assets.
55 // Defaults to "assets"
56 Asset_dirs []string
57
58 // list of directories relative to the Blueprints file containing
Colin Cross86a63ff2017-09-27 17:33:10 -070059 // Android resources
60 Resource_dirs []string
Colin Crosscb933592017-11-22 13:49:43 -080061
62 Instrumentation_for *string
Colin Cross7d5136f2015-05-11 13:39:40 -070063}
64
Colin Cross30e076a2015-04-13 13:58:27 -070065type AndroidApp struct {
Colin Cross46c9b8b2017-06-22 16:51:17 -070066 Module
Colin Cross30e076a2015-04-13 13:58:27 -070067
Colin Cross7d5136f2015-05-11 13:39:40 -070068 appProperties androidAppProperties
Colin Cross30e076a2015-04-13 13:58:27 -070069
Colin Cross3bc7ffa2017-11-22 16:19:37 -080070 aaptSrcJar android.Path
71 exportPackage android.Path
Colin Cross30e076a2015-04-13 13:58:27 -070072}
73
Colin Cross46c9b8b2017-06-22 16:51:17 -070074func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) {
75 a.Module.deps(ctx)
Colin Cross30e076a2015-04-13 13:58:27 -070076
Colin Cross3bc7ffa2017-11-22 16:19:37 -080077 if !Bool(a.properties.No_framework_libs) && !Bool(a.properties.No_standard_libs) {
Nan Zhangea568a42017-11-08 21:20:04 -080078 switch String(a.deviceProperties.Sdk_version) { // TODO: Res_sdk_version?
Colin Cross30e076a2015-04-13 13:58:27 -070079 case "current", "system_current", "":
Colin Crossbe1da472017-07-07 15:59:46 -070080 ctx.AddDependency(ctx.Module(), frameworkResTag, "framework-res")
Colin Cross30e076a2015-04-13 13:58:27 -070081 default:
82 // We'll already have a dependency on an sdk prebuilt android.jar
83 }
84 }
Colin Cross30e076a2015-04-13 13:58:27 -070085}
86
Colin Cross46c9b8b2017-06-22 16:51:17 -070087func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Colin Cross3bc7ffa2017-11-22 16:19:37 -080088 linkFlags, linkDeps, resDirs, overlayDirs := a.aapt2Flags(ctx)
Colin Cross30e076a2015-04-13 13:58:27 -070089
Colin Cross3bc7ffa2017-11-22 16:19:37 -080090 packageRes := android.PathForModuleOut(ctx, "package-res.apk")
91 srcJar := android.PathForModuleGen(ctx, "R.jar")
92 proguardOptionsFile := android.PathForModuleGen(ctx, "proguard.options")
Colin Cross30e076a2015-04-13 13:58:27 -070093
Colin Cross3bc7ffa2017-11-22 16:19:37 -080094 var compiledRes, compiledOverlay android.Paths
95 for _, dir := range resDirs {
96 compiledRes = append(compiledRes, aapt2Compile(ctx, dir.dir, dir.files).Paths()...)
Colin Cross30e076a2015-04-13 13:58:27 -070097 }
Colin Cross3bc7ffa2017-11-22 16:19:37 -080098 for _, dir := range overlayDirs {
99 compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir.dir, dir.files).Paths()...)
100 }
101
102 aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile,
103 linkFlags, linkDeps, compiledRes, compiledOverlay)
104
105 a.exportPackage = packageRes
106 a.aaptSrcJar = srcJar
107
108 ctx.CheckbuildFile(proguardOptionsFile)
109 ctx.CheckbuildFile(a.exportPackage)
110 ctx.CheckbuildFile(a.aaptSrcJar)
Colin Cross30e076a2015-04-13 13:58:27 -0700111
Colin Cross46c9b8b2017-06-22 16:51:17 -0700112 // apps manifests are handled by aapt, don't let Module see them
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700113 a.properties.Manifest = nil
Colin Cross30e076a2015-04-13 13:58:27 -0700114
115 //if !ctx.ContainsProperty("proguard.enabled") {
116 // a.properties.Proguard.Enabled = true
117 //}
118
Colin Cross46c9b8b2017-06-22 16:51:17 -0700119 a.Module.compile(ctx)
Colin Cross30e076a2015-04-13 13:58:27 -0700120
Nan Zhangea568a42017-11-08 21:20:04 -0800121 certificate := String(a.appProperties.Certificate)
Colin Cross30e076a2015-04-13 13:58:27 -0700122 if certificate == "" {
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700123 certificate = ctx.AConfig().DefaultAppCertificate(ctx).String()
Colin Cross30e076a2015-04-13 13:58:27 -0700124 } else if dir, _ := filepath.Split(certificate); dir == "" {
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700125 certificate = filepath.Join(ctx.AConfig().DefaultAppCertificateDir(ctx).String(), certificate)
Colin Cross30e076a2015-04-13 13:58:27 -0700126 } else {
Colin Cross635c3b02016-05-18 15:37:25 -0700127 certificate = filepath.Join(android.PathForSource(ctx).String(), certificate)
Colin Cross30e076a2015-04-13 13:58:27 -0700128 }
129
130 certificates := []string{certificate}
131 for _, c := range a.appProperties.Additional_certificates {
Colin Cross635c3b02016-05-18 15:37:25 -0700132 certificates = append(certificates, filepath.Join(android.PathForSource(ctx).String(), c))
Colin Cross30e076a2015-04-13 13:58:27 -0700133 }
134
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800135 packageFile := android.PathForModuleOut(ctx, "package.apk")
136
137 CreateAppPackage(ctx, packageFile, a.exportPackage, a.outputFile, certificates)
138
139 a.outputFile = packageFile
140
Colin Cross5c517922017-08-31 12:29:17 -0700141 ctx.InstallFile(android.PathForModuleInstall(ctx, "app"), ctx.ModuleName()+".apk", a.outputFile)
Colin Cross30e076a2015-04-13 13:58:27 -0700142}
143
144var aaptIgnoreFilenames = []string{
145 ".svn",
146 ".git",
147 ".ds_store",
148 "*.scc",
149 ".*",
150 "CVS",
151 "thumbs.db",
152 "picasa.ini",
153 "*~",
154}
155
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800156type globbedResourceDir struct {
157 dir android.Path
158 files android.Paths
159}
160
161func (a *AndroidApp) aapt2Flags(ctx android.ModuleContext) (flags []string, deps android.Paths,
162 resDirs, overlayDirs []globbedResourceDir) {
163
Colin Cross30e076a2015-04-13 13:58:27 -0700164 hasVersionCode := false
165 hasVersionName := false
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800166 hasProduct := false
167 for _, f := range a.appProperties.Aaptflags {
Colin Cross30e076a2015-04-13 13:58:27 -0700168 if strings.HasPrefix(f, "--version-code") {
169 hasVersionCode = true
170 } else if strings.HasPrefix(f, "--version-name") {
171 hasVersionName = true
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800172 } else if strings.HasPrefix(f, "--product") {
173 hasProduct = true
Colin Cross30e076a2015-04-13 13:58:27 -0700174 }
175 }
176
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800177 var linkFlags []string
Colin Cross30e076a2015-04-13 13:58:27 -0700178
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800179 // Flags specified in Android.bp
180 linkFlags = append(linkFlags, a.appProperties.Aaptflags...)
181
182 linkFlags = append(linkFlags, "--no-static-lib-packages")
183
184 // Find implicit or explicit asset and resource dirs
Colin Cross635c3b02016-05-18 15:37:25 -0700185 assetDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.appProperties.Asset_dirs, "assets")
Colin Cross86a63ff2017-09-27 17:33:10 -0700186 resourceDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.appProperties.Resource_dirs, "res")
Colin Cross30e076a2015-04-13 13:58:27 -0700187
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800188 var linkDeps android.Paths
189
190 // Glob directories into lists of paths
191 for _, dir := range resourceDirs {
192 resDirs = append(resDirs, globbedResourceDir{
193 dir: dir,
194 files: resourceGlob(ctx, dir),
195 })
196 overlayDirs = append(overlayDirs, overlayResourceGlob(ctx, dir)...)
Colin Cross30e076a2015-04-13 13:58:27 -0700197 }
198
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800199 var assetFiles android.Paths
200 for _, dir := range assetDirs {
201 assetFiles = append(assetFiles, resourceGlob(ctx, dir)...)
Colin Cross30e076a2015-04-13 13:58:27 -0700202 }
203
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800204 // App manifest file
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700205 var manifestFile string
206 if a.properties.Manifest == nil {
Colin Cross30e076a2015-04-13 13:58:27 -0700207 manifestFile = "AndroidManifest.xml"
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700208 } else {
209 manifestFile = *a.properties.Manifest
Colin Cross30e076a2015-04-13 13:58:27 -0700210 }
211
Colin Cross635c3b02016-05-18 15:37:25 -0700212 manifestPath := android.PathForModuleSrc(ctx, manifestFile)
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800213 linkFlags = append(linkFlags, "--manifest "+manifestPath.String())
214 linkDeps = append(linkDeps, manifestPath)
Colin Cross30e076a2015-04-13 13:58:27 -0700215
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800216 linkFlags = append(linkFlags, android.JoinWithPrefix(assetDirs.Strings(), "-A "))
217 linkDeps = append(linkDeps, assetFiles...)
Colin Cross30e076a2015-04-13 13:58:27 -0700218
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800219 // Include dirs
Colin Crossd11fcda2017-10-23 17:59:01 -0700220 ctx.VisitDirectDeps(func(module android.Module) {
Colin Cross74d73e22017-08-02 11:05:49 -0700221 var depFiles android.Paths
Colin Crossfc3674a2017-09-18 17:41:52 -0700222 if javaDep, ok := module.(Dependency); ok {
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800223 // TODO: shared android libraries
Colin Cross30e076a2015-04-13 13:58:27 -0700224 if ctx.OtherModuleName(module) == "framework-res" {
Colin Cross74d73e22017-08-02 11:05:49 -0700225 depFiles = android.Paths{javaDep.(*AndroidApp).exportPackage}
Colin Cross30e076a2015-04-13 13:58:27 -0700226 }
227 }
Colin Cross74d73e22017-08-02 11:05:49 -0700228
229 for _, dep := range depFiles {
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800230 linkFlags = append(linkFlags, "-I "+dep.String())
Colin Cross30e076a2015-04-13 13:58:27 -0700231 }
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800232 linkDeps = append(linkDeps, depFiles...)
Colin Cross30e076a2015-04-13 13:58:27 -0700233 })
234
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800235 // SDK version flags
Nan Zhangea568a42017-11-08 21:20:04 -0800236 sdkVersion := String(a.deviceProperties.Sdk_version)
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800237 switch sdkVersion {
238 case "", "current", "system_current", "test_current":
239 sdkVersion = ctx.AConfig().AppsDefaultVersionName()
Colin Cross30e076a2015-04-13 13:58:27 -0700240 }
241
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800242 linkFlags = append(linkFlags, "--min-sdk-version "+sdkVersion)
243 linkFlags = append(linkFlags, "--target-sdk-version "+sdkVersion)
Colin Cross30e076a2015-04-13 13:58:27 -0700244
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800245 // Product characteristics
246 if !hasProduct && len(ctx.AConfig().ProductAAPTCharacteristics()) > 0 {
247 linkFlags = append(linkFlags, "--product", ctx.AConfig().ProductAAPTCharacteristics())
248 }
249
250 // Product AAPT config
251 for _, aaptConfig := range ctx.AConfig().ProductAAPTConfig() {
252 linkFlags = append(linkFlags, "-c", aaptConfig)
253 }
254
255 // Product AAPT preferred config
256 if len(ctx.AConfig().ProductAAPTPreferredConfig()) > 0 {
257 linkFlags = append(linkFlags, "--preferred-density", ctx.AConfig().ProductAAPTPreferredConfig())
258 }
259
260 // Version code
Colin Cross30e076a2015-04-13 13:58:27 -0700261 if !hasVersionCode {
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800262 linkFlags = append(linkFlags, "--version-code", ctx.AConfig().PlatformSdkVersion())
Colin Cross30e076a2015-04-13 13:58:27 -0700263 }
264
265 if !hasVersionName {
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800266 versionName := proptools.NinjaEscape([]string{ctx.AConfig().AppsDefaultVersionName()})[0]
267 linkFlags = append(linkFlags, "--version-name ", versionName)
268 }
269
270 if String(a.appProperties.Instrumentation_for) != "" {
271 linkFlags = append(linkFlags,
272 "--rename-instrumentation-target-package",
273 String(a.appProperties.Instrumentation_for))
Colin Cross30e076a2015-04-13 13:58:27 -0700274 }
275
276 // TODO: LOCAL_PACKAGE_OVERRIDES
277 // $(addprefix --rename-manifest-package , $(PRIVATE_MANIFEST_PACKAGE_NAME)) \
278
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800279 return linkFlags, linkDeps, resDirs, overlayDirs
Colin Cross30e076a2015-04-13 13:58:27 -0700280}
281
Colin Cross36242852017-06-23 15:06:31 -0700282func AndroidAppFactory() android.Module {
Colin Cross30e076a2015-04-13 13:58:27 -0700283 module := &AndroidApp{}
284
Colin Cross36242852017-06-23 15:06:31 -0700285 module.AddProperties(
Colin Cross540eff82017-06-22 17:01:52 -0700286 &module.Module.properties,
287 &module.Module.deviceProperties,
288 &module.appProperties)
Colin Cross36242852017-06-23 15:06:31 -0700289
290 android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
291 return module
Colin Cross30e076a2015-04-13 13:58:27 -0700292}
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800293
294func resourceGlob(ctx android.ModuleContext, dir android.Path) android.Paths {
295 var ret android.Paths
296 files := ctx.Glob(filepath.Join(dir.String(), "**/*"), aaptIgnoreFilenames)
297 for _, f := range files {
298 if isDir, err := ctx.Fs().IsDir(f.String()); err != nil {
299 ctx.ModuleErrorf("error in IsDir(%s): %s", f.String(), err.Error())
300 return nil
301 } else if !isDir {
302 ret = append(ret, f)
303 }
304 }
305 return ret
306}
307
308type overlayGlobResult struct {
309 dir string
310 paths android.DirectorySortedPaths
311}
312
313const overlayDataKey = "overlayDataKey"
314
315func overlayResourceGlob(ctx android.ModuleContext, dir android.Path) []globbedResourceDir {
316 overlayData := ctx.AConfig().Get(overlayDataKey).([]overlayGlobResult)
317
318 var ret []globbedResourceDir
319
320 for _, data := range overlayData {
321 files := data.paths.PathsInDirectory(filepath.Join(data.dir, dir.String()))
322 if len(files) > 0 {
323 ret = append(ret, globbedResourceDir{
324 dir: android.PathForSource(ctx, data.dir, dir.String()),
325 files: files,
326 })
327 }
328 }
329
330 return ret
331}
332
333func OverlaySingletonFactory() android.Singleton {
334 return overlaySingleton{}
335}
336
337type overlaySingleton struct{}
338
339func (overlaySingleton) GenerateBuildActions(ctx android.SingletonContext) {
340 var overlayData []overlayGlobResult
341 for _, overlay := range ctx.Config().(android.Config).ResourceOverlays() {
342 var result overlayGlobResult
343 result.dir = overlay
344 files, err := ctx.GlobWithDeps(filepath.Join(overlay, "**/*"), aaptIgnoreFilenames)
345 if err != nil {
346 ctx.Errorf("failed to glob resource dir %q: %s", overlay, err.Error())
347 continue
348 }
349 var paths android.Paths
350 for _, f := range files {
351 if isDir, err := ctx.Fs().IsDir(f); err != nil {
352 ctx.Errorf("error in IsDir(%s): %s", f, err.Error())
353 return
354 } else if !isDir {
355 paths = append(paths, android.PathForSource(ctx, f))
356 }
357 }
358 result.paths = android.PathsToDirectorySortedPaths(paths)
359 overlayData = append(overlayData, result)
360 }
361
362 ctx.Config().(android.Config).Once(overlayDataKey, func() interface{} {
363 return overlayData
364 })
365}