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	"strings"
20
21	"github.com/google/blueprint"
22
23	"android/soong/android"
24	"android/soong/dexpreopt"
25)
26
27var manifestFixerRule = pctx.AndroidStaticRule("manifestFixer",
28	blueprint.RuleParams{
29		Command: `${config.ManifestFixerCmd} ` +
30			`--minSdkVersion ${minSdkVersion} ` +
31			`--targetSdkVersion ${targetSdkVersion} ` +
32			`--raise-min-sdk-version ` +
33			`$args $in $out`,
34		CommandDeps: []string{"${config.ManifestFixerCmd}"},
35	},
36	"minSdkVersion", "targetSdkVersion", "args")
37
38var manifestMergerRule = pctx.AndroidStaticRule("manifestMerger",
39	blueprint.RuleParams{
40		Command:     `${config.ManifestMergerCmd} $args --main $in $libs --out $out`,
41		CommandDeps: []string{"${config.ManifestMergerCmd}"},
42	},
43	"args", "libs")
44
45// Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml
46func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext android.SdkContext,
47	classLoaderContexts dexpreopt.ClassLoaderContextMap, isLibrary, useEmbeddedNativeLibs, usesNonSdkApis,
48	useEmbeddedDex, hasNoCode bool, loggingParent string) android.Path {
49
50	var args []string
51	if isLibrary {
52		args = append(args, "--library")
53	} else {
54		minSdkVersion, err := sdkContext.MinSdkVersion(ctx).EffectiveVersion(ctx)
55		if err != nil {
56			ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
57		}
58		if minSdkVersion.FinalOrFutureInt() >= 23 {
59			args = append(args, fmt.Sprintf("--extract-native-libs=%v", !useEmbeddedNativeLibs))
60		} else if useEmbeddedNativeLibs {
61			ctx.ModuleErrorf("module attempted to store uncompressed native libraries, but minSdkVersion=%d doesn't support it",
62				minSdkVersion)
63		}
64	}
65
66	if usesNonSdkApis {
67		args = append(args, "--uses-non-sdk-api")
68	}
69
70	if useEmbeddedDex {
71		args = append(args, "--use-embedded-dex")
72	}
73
74	for _, usesLib := range classLoaderContexts.UsesLibs() {
75		if inList(usesLib, dexpreopt.OptionalCompatUsesLibs) {
76			args = append(args, "--optional-uses-library", usesLib)
77		} else {
78			args = append(args, "--uses-library", usesLib)
79		}
80	}
81
82	if hasNoCode {
83		args = append(args, "--has-no-code")
84	}
85
86	if loggingParent != "" {
87		args = append(args, "--logging-parent", loggingParent)
88	}
89	var deps android.Paths
90	targetSdkVersion, err := sdkContext.TargetSdkVersion(ctx).EffectiveVersionString(ctx)
91	if err != nil {
92		ctx.ModuleErrorf("invalid targetSdkVersion: %s", err)
93	}
94	if UseApiFingerprint(ctx) && ctx.ModuleName() != "framework-res" {
95		targetSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(ctx).String())
96		deps = append(deps, ApiFingerprintPath(ctx))
97	}
98
99	minSdkVersion, err := sdkContext.MinSdkVersion(ctx).EffectiveVersionString(ctx)
100	if err != nil {
101		ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
102	}
103	if UseApiFingerprint(ctx) && ctx.ModuleName() != "framework-res" {
104		minSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(ctx).String())
105		deps = append(deps, ApiFingerprintPath(ctx))
106	}
107
108	fixedManifest := android.PathForModuleOut(ctx, "manifest_fixer", "AndroidManifest.xml")
109	if err != nil {
110		ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
111	}
112	ctx.Build(pctx, android.BuildParams{
113		Rule:        manifestFixerRule,
114		Description: "fix manifest",
115		Input:       manifest,
116		Implicits:   deps,
117		Output:      fixedManifest,
118		Args: map[string]string{
119			"minSdkVersion":    minSdkVersion,
120			"targetSdkVersion": targetSdkVersion,
121			"args":             strings.Join(args, " "),
122		},
123	})
124
125	return fixedManifest.WithoutRel()
126}
127
128func manifestMerger(ctx android.ModuleContext, manifest android.Path, staticLibManifests android.Paths,
129	isLibrary bool) android.Path {
130
131	var args string
132	if !isLibrary {
133		// Follow Gradle's behavior, only pass --remove-tools-declarations when merging app manifests.
134		args = "--remove-tools-declarations"
135	}
136
137	mergedManifest := android.PathForModuleOut(ctx, "manifest_merger", "AndroidManifest.xml")
138	ctx.Build(pctx, android.BuildParams{
139		Rule:        manifestMergerRule,
140		Description: "merge manifest",
141		Input:       manifest,
142		Implicits:   staticLibManifests,
143		Output:      mergedManifest,
144		Args: map[string]string{
145			"libs": android.JoinWithPrefix(staticLibManifests.Strings(), "--libs "),
146			"args": args,
147		},
148	})
149
150	return mergedManifest.WithoutRel()
151}
152