1// Copyright 2019 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 "android/soong/android" 19 "android/soong/java/config" 20 "fmt" 21 "path/filepath" 22 "runtime" 23 "sort" 24 "strconv" 25 "strings" 26 27 "github.com/google/blueprint/pathtools" 28) 29 30func init() { 31 android.RegisterPreSingletonType("sdk_versions", sdkPreSingletonFactory) 32 android.RegisterSingletonType("sdk", sdkSingletonFactory) 33 android.RegisterMakeVarsProvider(pctx, sdkMakeVars) 34} 35 36var sdkVersionsKey = android.NewOnceKey("sdkVersionsKey") 37var sdkFrameworkAidlPathKey = android.NewOnceKey("sdkFrameworkAidlPathKey") 38var apiFingerprintPathKey = android.NewOnceKey("apiFingerprintPathKey") 39 40type sdkContext interface { 41 // sdkVersion eturns the sdk_version property of the current module, or an empty string if it is not set. 42 sdkVersion() string 43 // minSdkVersion returns the min_sdk_version property of the current module, or sdkVersion() if it is not set. 44 minSdkVersion() string 45 // targetSdkVersion returns the target_sdk_version property of the current module, or sdkVersion() if it is not set. 46 targetSdkVersion() string 47} 48 49func sdkVersionOrDefault(ctx android.BaseContext, v string) string { 50 switch v { 51 case "", "current", "system_current", "test_current", "core_current": 52 return ctx.Config().DefaultAppTargetSdk() 53 default: 54 return v 55 } 56} 57 58// Returns a sdk version as a number. For modules targeting an unreleased SDK (meaning it does not yet have a number) 59// it returns android.FutureApiLevel (10000). 60func sdkVersionToNumber(ctx android.BaseContext, v string) (int, error) { 61 switch v { 62 case "", "current", "test_current", "system_current", "core_current": 63 return ctx.Config().DefaultAppTargetSdkInt(), nil 64 default: 65 n := android.GetNumericSdkVersion(v) 66 if i, err := strconv.Atoi(n); err != nil { 67 return -1, fmt.Errorf("invalid sdk version %q", n) 68 } else { 69 return i, nil 70 } 71 } 72} 73 74func sdkVersionToNumberAsString(ctx android.BaseContext, v string) (string, error) { 75 n, err := sdkVersionToNumber(ctx, v) 76 if err != nil { 77 return "", err 78 } 79 return strconv.Itoa(n), nil 80} 81 82func decodeSdkDep(ctx android.BaseContext, sdkContext sdkContext) sdkDep { 83 v := sdkContext.sdkVersion() 84 // For PDK builds, use the latest SDK version instead of "current" 85 if ctx.Config().IsPdkBuild() && (v == "" || v == "current") { 86 sdkVersions := ctx.Config().Get(sdkVersionsKey).([]int) 87 latestSdkVersion := 0 88 if len(sdkVersions) > 0 { 89 latestSdkVersion = sdkVersions[len(sdkVersions)-1] 90 } 91 v = strconv.Itoa(latestSdkVersion) 92 } 93 94 numericSdkVersion, err := sdkVersionToNumber(ctx, v) 95 if err != nil { 96 ctx.PropertyErrorf("sdk_version", "%s", err) 97 return sdkDep{} 98 } 99 100 toPrebuilt := func(sdk string) sdkDep { 101 var api, v string 102 if strings.Contains(sdk, "_") { 103 t := strings.Split(sdk, "_") 104 api = t[0] 105 v = t[1] 106 } else { 107 api = "public" 108 v = sdk 109 } 110 dir := filepath.Join("prebuilts", "sdk", v, api) 111 jar := filepath.Join(dir, "android.jar") 112 // There's no aidl for other SDKs yet. 113 // TODO(77525052): Add aidl files for other SDKs too. 114 public_dir := filepath.Join("prebuilts", "sdk", v, "public") 115 aidl := filepath.Join(public_dir, "framework.aidl") 116 jarPath := android.ExistentPathForSource(ctx, jar) 117 aidlPath := android.ExistentPathForSource(ctx, aidl) 118 lambdaStubsPath := android.PathForSource(ctx, config.SdkLambdaStubsPath) 119 120 if (!jarPath.Valid() || !aidlPath.Valid()) && ctx.Config().AllowMissingDependencies() { 121 return sdkDep{ 122 invalidVersion: true, 123 modules: []string{fmt.Sprintf("sdk_%s_%s_android", api, v)}, 124 } 125 } 126 127 if !jarPath.Valid() { 128 ctx.PropertyErrorf("sdk_version", "invalid sdk version %q, %q does not exist", v, jar) 129 return sdkDep{} 130 } 131 132 if !aidlPath.Valid() { 133 ctx.PropertyErrorf("sdk_version", "invalid sdk version %q, %q does not exist", v, aidl) 134 return sdkDep{} 135 } 136 137 return sdkDep{ 138 useFiles: true, 139 jars: android.Paths{jarPath.Path(), lambdaStubsPath}, 140 aidl: android.OptionalPathForPath(aidlPath.Path()), 141 } 142 } 143 144 toModule := func(m, r string, aidl android.Path) sdkDep { 145 ret := sdkDep{ 146 useModule: true, 147 modules: []string{m, config.DefaultLambdaStubsLibrary}, 148 systemModules: m + "_system_modules", 149 frameworkResModule: r, 150 aidl: android.OptionalPathForPath(aidl), 151 } 152 153 if m == "core.current.stubs" { 154 ret.systemModules = "core-system-modules" 155 } else if m == "core.platform.api.stubs" { 156 ret.systemModules = "core-platform-api-stubs-system-modules" 157 } 158 return ret 159 } 160 161 // Ensures that the specificed system SDK version is one of BOARD_SYSTEMSDK_VERSIONS (for vendor apks) 162 // or PRODUCT_SYSTEMSDK_VERSIONS (for other apks or when BOARD_SYSTEMSDK_VERSIONS is not set) 163 if strings.HasPrefix(v, "system_") && numericSdkVersion != android.FutureApiLevel { 164 allowed_versions := ctx.DeviceConfig().PlatformSystemSdkVersions() 165 if ctx.DeviceSpecific() || ctx.SocSpecific() { 166 if len(ctx.DeviceConfig().SystemSdkVersions()) > 0 { 167 allowed_versions = ctx.DeviceConfig().SystemSdkVersions() 168 } 169 } 170 if len(allowed_versions) > 0 && !android.InList(strconv.Itoa(numericSdkVersion), allowed_versions) { 171 ctx.PropertyErrorf("sdk_version", "incompatible sdk version %q. System SDK version should be one of %q", 172 v, allowed_versions) 173 } 174 } 175 176 if ctx.Config().UnbundledBuildUsePrebuiltSdks() && v != "" { 177 return toPrebuilt(v) 178 } 179 180 switch v { 181 case "": 182 return sdkDep{ 183 useDefaultLibs: true, 184 frameworkResModule: "framework-res", 185 } 186 case "current": 187 return toModule("android_stubs_current", "framework-res", sdkFrameworkAidlPath(ctx)) 188 case "system_current": 189 return toModule("android_system_stubs_current", "framework-res", sdkFrameworkAidlPath(ctx)) 190 case "test_current": 191 return toModule("android_test_stubs_current", "framework-res", sdkFrameworkAidlPath(ctx)) 192 case "core_current": 193 return toModule("core.current.stubs", "", nil) 194 default: 195 return toPrebuilt(v) 196 } 197} 198 199func sdkPreSingletonFactory() android.Singleton { 200 return sdkPreSingleton{} 201} 202 203type sdkPreSingleton struct{} 204 205func (sdkPreSingleton) GenerateBuildActions(ctx android.SingletonContext) { 206 sdkJars, err := ctx.GlobWithDeps("prebuilts/sdk/*/public/android.jar", nil) 207 if err != nil { 208 ctx.Errorf("failed to glob prebuilts/sdk/*/public/android.jar: %s", err.Error()) 209 } 210 211 var sdkVersions []int 212 for _, sdkJar := range sdkJars { 213 dir := filepath.Base(filepath.Dir(filepath.Dir(sdkJar))) 214 v, err := strconv.Atoi(dir) 215 if scerr, ok := err.(*strconv.NumError); ok && scerr.Err == strconv.ErrSyntax { 216 continue 217 } else if err != nil { 218 ctx.Errorf("invalid sdk jar %q, %s, %v", sdkJar, err.Error()) 219 } 220 sdkVersions = append(sdkVersions, v) 221 } 222 223 sort.Ints(sdkVersions) 224 225 ctx.Config().Once(sdkVersionsKey, func() interface{} { return sdkVersions }) 226} 227 228func sdkSingletonFactory() android.Singleton { 229 return sdkSingleton{} 230} 231 232type sdkSingleton struct{} 233 234func (sdkSingleton) GenerateBuildActions(ctx android.SingletonContext) { 235 if ctx.Config().UnbundledBuildUsePrebuiltSdks() || ctx.Config().IsPdkBuild() { 236 return 237 } 238 239 createSdkFrameworkAidl(ctx) 240 createAPIFingerprint(ctx) 241} 242 243// Create framework.aidl by extracting anything that implements android.os.Parcelable from the SDK stubs modules. 244func createSdkFrameworkAidl(ctx android.SingletonContext) { 245 stubsModules := []string{ 246 "android_stubs_current", 247 "android_test_stubs_current", 248 "android_system_stubs_current", 249 } 250 251 stubsJars := make([]android.Paths, len(stubsModules)) 252 253 ctx.VisitAllModules(func(module android.Module) { 254 // Collect dex jar paths for the modules listed above. 255 if j, ok := module.(Dependency); ok { 256 name := ctx.ModuleName(module) 257 if i := android.IndexList(name, stubsModules); i != -1 { 258 stubsJars[i] = j.HeaderJars() 259 } 260 } 261 }) 262 263 var missingDeps []string 264 265 for i := range stubsJars { 266 if stubsJars[i] == nil { 267 if ctx.Config().AllowMissingDependencies() { 268 missingDeps = append(missingDeps, stubsModules[i]) 269 } else { 270 ctx.Errorf("failed to find dex jar path for module %q", 271 stubsModules[i]) 272 } 273 } 274 } 275 276 rule := android.NewRuleBuilder() 277 rule.MissingDeps(missingDeps) 278 279 var aidls android.Paths 280 for _, jars := range stubsJars { 281 for _, jar := range jars { 282 aidl := android.PathForOutput(ctx, "aidl", pathtools.ReplaceExtension(jar.Base(), "aidl")) 283 284 rule.Command(). 285 Text("rm -f").Output(aidl) 286 rule.Command(). 287 Tool(ctx.Config().HostToolPath(ctx, "sdkparcelables")). 288 Input(jar). 289 Output(aidl) 290 291 aidls = append(aidls, aidl) 292 } 293 } 294 295 combinedAidl := sdkFrameworkAidlPath(ctx) 296 tempPath := combinedAidl.ReplaceExtension(ctx, "aidl.tmp") 297 298 rule.Command(). 299 Text("rm -f").Output(tempPath) 300 rule.Command(). 301 Text("cat"). 302 Inputs(aidls). 303 Text("| sort -u >"). 304 Output(tempPath) 305 306 commitChangeForRestat(rule, tempPath, combinedAidl) 307 308 rule.Build(pctx, ctx, "framework_aidl", "generate framework.aidl") 309} 310 311func sdkFrameworkAidlPath(ctx android.PathContext) android.OutputPath { 312 return ctx.Config().Once(sdkFrameworkAidlPathKey, func() interface{} { 313 return android.PathForOutput(ctx, "framework.aidl") 314 }).(android.OutputPath) 315} 316 317// Create api_fingerprint.txt 318func createAPIFingerprint(ctx android.SingletonContext) { 319 out := ApiFingerprintPath(ctx) 320 321 rule := android.NewRuleBuilder() 322 323 rule.Command(). 324 Text("rm -f").Output(out) 325 cmd := rule.Command() 326 327 if ctx.Config().PlatformSdkCodename() == "REL" { 328 cmd.Text("echo REL >").Output(out) 329 } else if ctx.Config().IsPdkBuild() { 330 // TODO: get this from the PDK artifacts? 331 cmd.Text("echo PDK >").Output(out) 332 } else if !ctx.Config().UnbundledBuildUsePrebuiltSdks() { 333 in, err := ctx.GlobWithDeps("frameworks/base/api/*current.txt", nil) 334 if err != nil { 335 ctx.Errorf("error globbing API files: %s", err) 336 } 337 338 cmd.Text("cat"). 339 Inputs(android.PathsForSource(ctx, in)). 340 Text("|") 341 342 if runtime.GOOS == "darwin" { 343 cmd.Text("md5") 344 } else { 345 cmd.Text("md5sum") 346 } 347 348 cmd.Text("| cut -d' ' -f1 >"). 349 Output(out) 350 } else { 351 // Unbundled build 352 // TODO: use a prebuilt api_fingerprint.txt from prebuilts/sdk/current.txt once we have one 353 cmd.Text("echo"). 354 Flag(ctx.Config().PlatformPreviewSdkVersion()). 355 Text(">"). 356 Output(out) 357 } 358 359 rule.Build(pctx, ctx, "api_fingerprint", "generate api_fingerprint.txt") 360} 361 362func ApiFingerprintPath(ctx android.PathContext) android.OutputPath { 363 return ctx.Config().Once(apiFingerprintPathKey, func() interface{} { 364 return android.PathForOutput(ctx, "api_fingerprint.txt") 365 }).(android.OutputPath) 366} 367 368func sdkMakeVars(ctx android.MakeVarsContext) { 369 if ctx.Config().UnbundledBuildUsePrebuiltSdks() || ctx.Config().IsPdkBuild() { 370 return 371 } 372 373 ctx.Strict("FRAMEWORK_AIDL", sdkFrameworkAidlPath(ctx).String()) 374 ctx.Strict("API_FINGERPRINT", ApiFingerprintPath(ctx).String()) 375} 376