• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2018 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
17import (
18	"fmt"
19	"strconv"
20	"strings"
21
22	"github.com/google/blueprint"
23
24	"android/soong/android"
25	"android/soong/dexpreopt"
26)
27
28var manifestFixerRule = pctx.AndroidStaticRule("manifestFixer",
29	blueprint.RuleParams{
30		Command: `${config.ManifestFixerCmd} ` +
31			`$args $in $out`,
32		CommandDeps: []string{"${config.ManifestFixerCmd}"},
33	},
34	"args")
35
36var manifestMergerRule = pctx.AndroidStaticRule("manifestMerger",
37	blueprint.RuleParams{
38		Command:     `${config.ManifestMergerCmd} $args --main $in $libs --out $out`,
39		CommandDeps: []string{"${config.ManifestMergerCmd}"},
40	},
41	"args", "libs")
42
43// targetSdkVersion for manifest_fixer
44// When TARGET_BUILD_APPS is not empty, this method returns 10000 for modules targeting an unreleased SDK
45// This enables release builds (that run with TARGET_BUILD_APPS=[val...]) to target APIs that have not yet been finalized as part of an SDK
46func targetSdkVersionForManifestFixer(ctx android.ModuleContext, params ManifestFixerParams) string {
47	targetSdkVersionLevel := params.SdkContext.TargetSdkVersion(ctx)
48
49	// Check if we want to return 10000
50	// TODO(b/240294501): Determine the rules for handling test apexes
51	if shouldReturnFinalOrFutureInt(ctx, targetSdkVersionLevel, params.EnforceDefaultTargetSdkVersion) {
52		return strconv.Itoa(android.FutureApiLevel.FinalOrFutureInt())
53	}
54	targetSdkVersion, err := targetSdkVersionLevel.EffectiveVersionString(ctx)
55	if err != nil {
56		ctx.ModuleErrorf("invalid targetSdkVersion: %s", err)
57	}
58	return targetSdkVersion
59}
60
61// Return true for modules targeting "current" if either
62// 1. The module is built in unbundled mode (TARGET_BUILD_APPS not empty)
63// 2. The module is run as part of MTS, and should be testable on stable branches
64// Do not return 10000 if we are enforcing default targetSdkVersion and sdk has been finalised
65func shouldReturnFinalOrFutureInt(ctx android.ModuleContext, targetSdkVersionLevel android.ApiLevel, enforceDefaultTargetSdkVersion bool) bool {
66	// If this is a REL branch, do not return 10000
67	if ctx.Config().PlatformSdkFinal() {
68		return false
69	}
70	// If this a module targeting an unreleased SDK (MTS or unbundled builds), return 10000
71	return targetSdkVersionLevel.IsPreview() && (ctx.Config().UnbundledBuildApps() || includedInMts(ctx.Module()))
72}
73
74// Helper function that casts android.Module to java.androidTestApp
75// If this type conversion is possible, it queries whether the test app is included in an MTS suite
76func includedInMts(module android.Module) bool {
77	if test, ok := module.(androidTestApp); ok {
78		return test.includedInTestSuite("mts")
79	}
80	return false
81}
82
83type ManifestFixerParams struct {
84	SdkContext                     android.SdkContext
85	ClassLoaderContexts            dexpreopt.ClassLoaderContextMap
86	IsLibrary                      bool
87	DefaultManifestVersion         string
88	UseEmbeddedNativeLibs          bool
89	UsesNonSdkApis                 bool
90	UseEmbeddedDex                 bool
91	HasNoCode                      bool
92	TestOnly                       bool
93	LoggingParent                  string
94	EnforceDefaultTargetSdkVersion bool
95}
96
97// Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml
98func ManifestFixer(ctx android.ModuleContext, manifest android.Path,
99	params ManifestFixerParams) android.Path {
100	var args []string
101
102	if params.IsLibrary {
103		args = append(args, "--library")
104	} else if params.SdkContext != nil {
105		minSdkVersion, err := params.SdkContext.MinSdkVersion(ctx).EffectiveVersion(ctx)
106		if err != nil {
107			ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
108		}
109		if minSdkVersion.FinalOrFutureInt() >= 23 {
110			args = append(args, fmt.Sprintf("--extract-native-libs=%v", !params.UseEmbeddedNativeLibs))
111		} else if params.UseEmbeddedNativeLibs {
112			ctx.ModuleErrorf("module attempted to store uncompressed native libraries, but minSdkVersion=%s doesn't support it",
113				minSdkVersion.String())
114		}
115	}
116
117	if params.UsesNonSdkApis {
118		args = append(args, "--uses-non-sdk-api")
119	}
120
121	if params.UseEmbeddedDex {
122		args = append(args, "--use-embedded-dex")
123	}
124
125	if params.ClassLoaderContexts != nil {
126		// Libraries propagated via `uses_libs`/`optional_uses_libs` are also added (they may be
127		// propagated from dependencies).
128		requiredUsesLibs, optionalUsesLibs := params.ClassLoaderContexts.UsesLibs()
129
130		for _, usesLib := range requiredUsesLibs {
131			args = append(args, "--uses-library", usesLib)
132		}
133		for _, usesLib := range optionalUsesLibs {
134			args = append(args, "--optional-uses-library", usesLib)
135		}
136	}
137
138	if params.HasNoCode {
139		args = append(args, "--has-no-code")
140	}
141
142	if params.TestOnly {
143		args = append(args, "--test-only")
144	}
145
146	if params.LoggingParent != "" {
147		args = append(args, "--logging-parent", params.LoggingParent)
148	}
149	var deps android.Paths
150	var argsMapper = make(map[string]string)
151
152	if params.SdkContext != nil {
153		targetSdkVersion := targetSdkVersionForManifestFixer(ctx, params)
154
155		if UseApiFingerprint(ctx) && ctx.ModuleName() != "framework-res" {
156			targetSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(ctx).String())
157			deps = append(deps, ApiFingerprintPath(ctx))
158		}
159
160		args = append(args, "--targetSdkVersion ", targetSdkVersion)
161
162		minSdkVersion, err := params.SdkContext.MinSdkVersion(ctx).EffectiveVersionString(ctx)
163		if err != nil {
164			ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
165		}
166
167		replaceMaxSdkVersionPlaceholder, err := params.SdkContext.ReplaceMaxSdkVersionPlaceholder(ctx).EffectiveVersion(ctx)
168		if err != nil {
169			ctx.ModuleErrorf("invalid ReplaceMaxSdkVersionPlaceholder: %s", err)
170		}
171
172		if UseApiFingerprint(ctx) && ctx.ModuleName() != "framework-res" {
173			minSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(ctx).String())
174			deps = append(deps, ApiFingerprintPath(ctx))
175		}
176
177		if err != nil {
178			ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
179		}
180		args = append(args, "--minSdkVersion ", minSdkVersion)
181		args = append(args, "--replaceMaxSdkVersionPlaceholder ", strconv.Itoa(replaceMaxSdkVersionPlaceholder.FinalOrFutureInt()))
182		args = append(args, "--raise-min-sdk-version")
183	}
184	if params.DefaultManifestVersion != "" {
185		args = append(args, "--override-placeholder-version", params.DefaultManifestVersion)
186	}
187
188	fixedManifest := android.PathForModuleOut(ctx, "manifest_fixer", "AndroidManifest.xml")
189	argsMapper["args"] = strings.Join(args, " ")
190
191	ctx.Build(pctx, android.BuildParams{
192		Rule:        manifestFixerRule,
193		Description: "fix manifest",
194		Input:       manifest,
195		Implicits:   deps,
196		Output:      fixedManifest,
197		Args:        argsMapper,
198	})
199
200	return fixedManifest.WithoutRel()
201}
202
203func manifestMerger(ctx android.ModuleContext, manifest android.Path, staticLibManifests android.Paths,
204	isLibrary bool) android.Path {
205
206	var args string
207	if !isLibrary {
208		// Follow Gradle's behavior, only pass --remove-tools-declarations when merging app manifests.
209		args = "--remove-tools-declarations"
210	}
211
212	mergedManifest := android.PathForModuleOut(ctx, "manifest_merger", "AndroidManifest.xml")
213	ctx.Build(pctx, android.BuildParams{
214		Rule:        manifestMergerRule,
215		Description: "merge manifest",
216		Input:       manifest,
217		Implicits:   staticLibManifests,
218		Output:      mergedManifest,
219		Args: map[string]string{
220			"libs": android.JoinWithPrefix(staticLibManifests.Strings(), "--libs "),
221			"args": args,
222		},
223	})
224
225	return mergedManifest.WithoutRel()
226}
227