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