• 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, fingerprintTargetSdkVersion, fingerprintDeps :=
156			UseApiFingerprint(ctx); useApiFingerprint && ctx.ModuleName() != "framework-res" {
157			targetSdkVersion = fingerprintTargetSdkVersion
158			deps = append(deps, fingerprintDeps)
159		}
160
161		args = append(args, "--targetSdkVersion ", targetSdkVersion)
162
163		minSdkVersion, err := params.SdkContext.MinSdkVersion(ctx).EffectiveVersionString(ctx)
164		if err != nil {
165			ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
166		}
167
168		replaceMaxSdkVersionPlaceholder, err := params.SdkContext.ReplaceMaxSdkVersionPlaceholder(ctx).EffectiveVersion(ctx)
169		if err != nil {
170			ctx.ModuleErrorf("invalid ReplaceMaxSdkVersionPlaceholder: %s", err)
171		}
172
173		if useApiFingerprint, fingerprintMinSdkVersion, fingerprintDeps :=
174			UseApiFingerprint(ctx); useApiFingerprint && ctx.ModuleName() != "framework-res" {
175			minSdkVersion = fingerprintMinSdkVersion
176			deps = append(deps, fingerprintDeps)
177		}
178
179		if err != nil {
180			ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
181		}
182		args = append(args, "--minSdkVersion ", minSdkVersion)
183		args = append(args, "--replaceMaxSdkVersionPlaceholder ", strconv.Itoa(replaceMaxSdkVersionPlaceholder.FinalOrFutureInt()))
184		args = append(args, "--raise-min-sdk-version")
185	}
186	if params.DefaultManifestVersion != "" {
187		args = append(args, "--override-placeholder-version", params.DefaultManifestVersion)
188	}
189
190	fixedManifest := android.PathForModuleOut(ctx, "manifest_fixer", "AndroidManifest.xml")
191	argsMapper["args"] = strings.Join(args, " ")
192
193	ctx.Build(pctx, android.BuildParams{
194		Rule:        manifestFixerRule,
195		Description: "fix manifest",
196		Input:       manifest,
197		Implicits:   deps,
198		Output:      fixedManifest,
199		Args:        argsMapper,
200	})
201
202	return fixedManifest.WithoutRel()
203}
204
205type ManifestMergerParams struct {
206	staticLibManifests android.Paths
207	isLibrary          bool
208	packageName        string
209}
210
211func manifestMerger(ctx android.ModuleContext, manifest android.Path,
212	params ManifestMergerParams) android.Path {
213
214	var args []string
215	if !params.isLibrary {
216		// Follow Gradle's behavior, only pass --remove-tools-declarations when merging app manifests.
217		args = append(args, "--remove-tools-declarations")
218	}
219
220	packageName := params.packageName
221	if packageName != "" {
222		args = append(args, "--property PACKAGE="+packageName)
223	}
224
225	mergedManifest := android.PathForModuleOut(ctx, "manifest_merger", "AndroidManifest.xml")
226	ctx.Build(pctx, android.BuildParams{
227		Rule:        manifestMergerRule,
228		Description: "merge manifest",
229		Input:       manifest,
230		Implicits:   params.staticLibManifests,
231		Output:      mergedManifest,
232		Args: map[string]string{
233			"libs": android.JoinWithPrefix(params.staticLibManifests.Strings(), "--libs "),
234			"args": strings.Join(args, " "),
235		},
236	})
237
238	return mergedManifest.WithoutRel()
239}
240