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 returns true if android_test, android_test_helper_app, java_test are in an MTS suite. 75func includedInMts(module android.Module) bool { 76 if test, ok := module.(androidTestApp); ok { 77 return test.includedInTestSuite("mts") 78 } 79 // java_test 80 if test, ok := module.(*Test); ok { 81 return android.PrefixInList(test.testProperties.Test_suites, "mts") 82 } 83 return false 84} 85 86type ManifestFixerParams struct { 87 SdkContext android.SdkContext 88 ClassLoaderContexts dexpreopt.ClassLoaderContextMap 89 IsLibrary bool 90 DefaultManifestVersion string 91 UseEmbeddedNativeLibs bool 92 UsesNonSdkApis bool 93 UseEmbeddedDex bool 94 HasNoCode bool 95 TestOnly bool 96 LoggingParent string 97 EnforceDefaultTargetSdkVersion bool 98} 99 100// Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml 101func ManifestFixer(ctx android.ModuleContext, manifest android.Path, 102 params ManifestFixerParams) android.Path { 103 var args []string 104 105 if params.IsLibrary { 106 args = append(args, "--library") 107 } else if params.SdkContext != nil { 108 minSdkVersion, err := params.SdkContext.MinSdkVersion(ctx).EffectiveVersion(ctx) 109 if err != nil { 110 ctx.ModuleErrorf("invalid minSdkVersion: %s", err) 111 } 112 if minSdkVersion.FinalOrFutureInt() >= 23 { 113 args = append(args, fmt.Sprintf("--extract-native-libs=%v", !params.UseEmbeddedNativeLibs)) 114 } else if params.UseEmbeddedNativeLibs { 115 ctx.ModuleErrorf("module attempted to store uncompressed native libraries, but minSdkVersion=%s doesn't support it", 116 minSdkVersion.String()) 117 } 118 } 119 120 if params.UsesNonSdkApis { 121 args = append(args, "--uses-non-sdk-api") 122 } 123 124 if params.UseEmbeddedDex { 125 args = append(args, "--use-embedded-dex") 126 } 127 128 if params.ClassLoaderContexts != nil { 129 // Libraries propagated via `uses_libs`/`optional_uses_libs` are also added (they may be 130 // propagated from dependencies). 131 requiredUsesLibs, optionalUsesLibs := params.ClassLoaderContexts.UsesLibs() 132 133 for _, usesLib := range requiredUsesLibs { 134 args = append(args, "--uses-library", usesLib) 135 } 136 for _, usesLib := range optionalUsesLibs { 137 args = append(args, "--optional-uses-library", usesLib) 138 } 139 } 140 141 if params.HasNoCode { 142 args = append(args, "--has-no-code") 143 } 144 145 if params.TestOnly { 146 args = append(args, "--test-only") 147 } 148 149 if params.LoggingParent != "" { 150 args = append(args, "--logging-parent", params.LoggingParent) 151 } 152 var deps android.Paths 153 var argsMapper = make(map[string]string) 154 155 if params.SdkContext != nil { 156 targetSdkVersion := targetSdkVersionForManifestFixer(ctx, params) 157 158 if useApiFingerprint, fingerprintTargetSdkVersion, fingerprintDeps := 159 UseApiFingerprint(ctx); useApiFingerprint && ctx.ModuleName() != "framework-res" { 160 targetSdkVersion = fingerprintTargetSdkVersion 161 deps = append(deps, fingerprintDeps) 162 } 163 164 args = append(args, "--targetSdkVersion ", targetSdkVersion) 165 166 minSdkVersion, err := params.SdkContext.MinSdkVersion(ctx).EffectiveVersionString(ctx) 167 if err != nil { 168 ctx.ModuleErrorf("invalid minSdkVersion: %s", err) 169 } 170 171 replaceMaxSdkVersionPlaceholder, err := params.SdkContext.ReplaceMaxSdkVersionPlaceholder(ctx).EffectiveVersion(ctx) 172 if err != nil { 173 ctx.ModuleErrorf("invalid ReplaceMaxSdkVersionPlaceholder: %s", err) 174 } 175 176 if useApiFingerprint, fingerprintMinSdkVersion, fingerprintDeps := 177 UseApiFingerprint(ctx); useApiFingerprint && ctx.ModuleName() != "framework-res" { 178 minSdkVersion = fingerprintMinSdkVersion 179 deps = append(deps, fingerprintDeps) 180 } 181 182 if err != nil { 183 ctx.ModuleErrorf("invalid minSdkVersion: %s", err) 184 } 185 args = append(args, "--minSdkVersion ", minSdkVersion) 186 args = append(args, "--replaceMaxSdkVersionPlaceholder ", strconv.Itoa(replaceMaxSdkVersionPlaceholder.FinalOrFutureInt())) 187 args = append(args, "--raise-min-sdk-version") 188 } 189 if params.DefaultManifestVersion != "" { 190 args = append(args, "--override-placeholder-version", params.DefaultManifestVersion) 191 } 192 193 fixedManifest := android.PathForModuleOut(ctx, "manifest_fixer", "AndroidManifest.xml") 194 argsMapper["args"] = strings.Join(args, " ") 195 196 ctx.Build(pctx, android.BuildParams{ 197 Rule: manifestFixerRule, 198 Description: "fix manifest", 199 Input: manifest, 200 Implicits: deps, 201 Output: fixedManifest, 202 Args: argsMapper, 203 }) 204 205 return fixedManifest.WithoutRel() 206} 207 208type ManifestMergerParams struct { 209 staticLibManifests android.Paths 210 isLibrary bool 211 packageName string 212} 213 214func manifestMerger(ctx android.ModuleContext, manifest android.Path, 215 params ManifestMergerParams) android.Path { 216 217 var args []string 218 if !params.isLibrary { 219 // Follow Gradle's behavior, only pass --remove-tools-declarations when merging app manifests. 220 args = append(args, "--remove-tools-declarations") 221 } 222 223 packageName := params.packageName 224 if packageName != "" { 225 args = append(args, "--property PACKAGE="+packageName) 226 } 227 228 mergedManifest := android.PathForModuleOut(ctx, "manifest_merger", "AndroidManifest.xml") 229 ctx.Build(pctx, android.BuildParams{ 230 Rule: manifestMergerRule, 231 Description: "merge manifest", 232 Input: manifest, 233 Implicits: params.staticLibManifests, 234 Output: mergedManifest, 235 Args: map[string]string{ 236 "libs": android.JoinWithPrefix(params.staticLibManifests.Strings(), "--libs "), 237 "args": strings.Join(args, " "), 238 }, 239 }) 240 241 return mergedManifest.WithoutRel() 242} 243