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 "android/soong/android" 19 "android/soong/genrule" 20 "fmt" 21 "io" 22 "path" 23 "path/filepath" 24 "sort" 25 "strings" 26 "sync" 27 28 "github.com/google/blueprint" 29 "github.com/google/blueprint/proptools" 30) 31 32var ( 33 sdkStubsLibrarySuffix = ".stubs" 34 sdkSystemApiSuffix = ".system" 35 sdkTestApiSuffix = ".test" 36 sdkDocsSuffix = ".docs" 37 sdkXmlFileSuffix = ".xml" 38) 39 40type stubsLibraryDependencyTag struct { 41 blueprint.BaseDependencyTag 42 name string 43} 44 45type syspropLibraryInterface interface { 46 SyspropJavaModule() *SdkLibrary 47} 48 49var ( 50 publicApiStubsTag = dependencyTag{name: "public"} 51 systemApiStubsTag = dependencyTag{name: "system"} 52 testApiStubsTag = dependencyTag{name: "test"} 53 publicApiFileTag = dependencyTag{name: "publicApi"} 54 systemApiFileTag = dependencyTag{name: "systemApi"} 55 testApiFileTag = dependencyTag{name: "testApi"} 56) 57 58type apiScope int 59 60const ( 61 apiScopePublic apiScope = iota 62 apiScopeSystem 63 apiScopeTest 64) 65 66var ( 67 javaSdkLibrariesLock sync.Mutex 68) 69 70// java_sdk_library is to make a Java library that implements optional platform APIs to apps. 71// It is actually a wrapper of several modules: 1) stubs library that clients are linked against 72// to, 2) droiddoc module that internally generates API stubs source files, 3) the real runtime 73// shared library that implements the APIs, and 4) XML file for adding the runtime lib to the 74// classpath at runtime if requested via <uses-library>. 75// 76// TODO: these are big features that are currently missing 77// 1) disallowing linking to the runtime shared lib 78// 2) HTML generation 79 80func init() { 81 android.RegisterModuleType("java_sdk_library", SdkLibraryFactory) 82 83 android.PreArchMutators(func(ctx android.RegisterMutatorsContext) { 84 ctx.TopDown("java_sdk_library", SdkLibraryMutator).Parallel() 85 }) 86 87 android.RegisterMakeVarsProvider(pctx, func(ctx android.MakeVarsContext) { 88 javaSdkLibraries := javaSdkLibraries(ctx.Config()) 89 sort.Strings(*javaSdkLibraries) 90 ctx.Strict("JAVA_SDK_LIBRARIES", strings.Join(*javaSdkLibraries, " ")) 91 }) 92} 93 94type sdkLibraryProperties struct { 95 // list of optional source files that are part of API but not part of runtime library. 96 Api_srcs []string `android:"arch_variant"` 97 98 // List of Java libraries that will be in the classpath when building stubs 99 Stub_only_libs []string `android:"arch_variant"` 100 101 // list of package names that will be documented and publicized as API 102 Api_packages []string 103 104 // list of package names that must be hidden from the API 105 Hidden_api_packages []string 106 107 // local files that are used within user customized droiddoc options. 108 Droiddoc_option_files []string 109 110 // additional droiddoc options 111 // Available variables for substitution: 112 // 113 // $(location <label>): the path to the droiddoc_option_files with name <label> 114 Droiddoc_options []string 115 116 // the java library (in classpath) for documentation that provides java srcs and srcjars. 117 Srcs_lib *string 118 119 // the base dirs under srcs_lib will be scanned for java srcs. 120 Srcs_lib_whitelist_dirs []string 121 122 // the sub dirs under srcs_lib_whitelist_dirs will be scanned for java srcs. 123 // Defaults to "android.annotation". 124 Srcs_lib_whitelist_pkgs []string 125 126 // a list of top-level directories containing files to merge qualifier annotations 127 // (i.e. those intended to be included in the stubs written) from. 128 Merge_annotations_dirs []string 129 130 // a list of top-level directories containing Java stub files to merge show/hide annotations from. 131 Merge_inclusion_annotations_dirs []string 132 133 // If set to true, the path of dist files is apistubs/core. Defaults to false. 134 Core_lib *bool 135 136 // don't create dist rules. 137 No_dist *bool `blueprint:"mutated"` 138 139 // TODO: determines whether to create HTML doc or not 140 //Html_doc *bool 141} 142 143type SdkLibrary struct { 144 Library 145 146 sdkLibraryProperties sdkLibraryProperties 147 148 publicApiStubsPath android.Paths 149 systemApiStubsPath android.Paths 150 testApiStubsPath android.Paths 151 152 publicApiStubsImplPath android.Paths 153 systemApiStubsImplPath android.Paths 154 testApiStubsImplPath android.Paths 155 156 publicApiFilePath android.Path 157 systemApiFilePath android.Path 158 testApiFilePath android.Path 159} 160 161var _ Dependency = (*SdkLibrary)(nil) 162var _ SdkLibraryDependency = (*SdkLibrary)(nil) 163 164func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { 165 useBuiltStubs := !ctx.Config().UnbundledBuildUsePrebuiltSdks() 166 // Add dependencies to the stubs library 167 if useBuiltStubs { 168 ctx.AddVariationDependencies(nil, publicApiStubsTag, module.stubsName(apiScopePublic)) 169 } 170 ctx.AddVariationDependencies(nil, publicApiFileTag, module.docsName(apiScopePublic)) 171 172 if !Bool(module.properties.No_standard_libs) { 173 if useBuiltStubs { 174 ctx.AddVariationDependencies(nil, systemApiStubsTag, module.stubsName(apiScopeSystem)) 175 ctx.AddVariationDependencies(nil, testApiStubsTag, module.stubsName(apiScopeTest)) 176 } 177 ctx.AddVariationDependencies(nil, systemApiFileTag, module.docsName(apiScopeSystem)) 178 ctx.AddVariationDependencies(nil, testApiFileTag, module.docsName(apiScopeTest)) 179 } 180 181 module.Library.deps(ctx) 182} 183 184func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { 185 module.Library.GenerateAndroidBuildActions(ctx) 186 187 // Record the paths to the header jars of the library (stubs and impl). 188 // When this java_sdk_library is dependened from others via "libs" property, 189 // the recorded paths will be returned depending on the link type of the caller. 190 ctx.VisitDirectDeps(func(to android.Module) { 191 otherName := ctx.OtherModuleName(to) 192 tag := ctx.OtherModuleDependencyTag(to) 193 194 if lib, ok := to.(Dependency); ok { 195 switch tag { 196 case publicApiStubsTag: 197 module.publicApiStubsPath = lib.HeaderJars() 198 module.publicApiStubsImplPath = lib.ImplementationJars() 199 case systemApiStubsTag: 200 module.systemApiStubsPath = lib.HeaderJars() 201 module.systemApiStubsImplPath = lib.ImplementationJars() 202 case testApiStubsTag: 203 module.testApiStubsPath = lib.HeaderJars() 204 module.testApiStubsImplPath = lib.ImplementationJars() 205 } 206 } 207 if doc, ok := to.(ApiFilePath); ok { 208 switch tag { 209 case publicApiFileTag: 210 module.publicApiFilePath = doc.ApiFilePath() 211 case systemApiFileTag: 212 module.systemApiFilePath = doc.ApiFilePath() 213 case testApiFileTag: 214 module.testApiFilePath = doc.ApiFilePath() 215 default: 216 ctx.ModuleErrorf("depends on module %q of unknown tag %q", otherName, tag) 217 } 218 } 219 }) 220} 221 222func (module *SdkLibrary) AndroidMk() android.AndroidMkData { 223 data := module.Library.AndroidMk() 224 data.Required = append(data.Required, module.xmlFileName()) 225 226 data.Custom = func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) { 227 android.WriteAndroidMkData(w, data) 228 229 module.Library.AndroidMkHostDex(w, name, data) 230 if !Bool(module.sdkLibraryProperties.No_dist) { 231 // Create a phony module that installs the impl library, for the case when this lib is 232 // in PRODUCT_PACKAGES. 233 owner := module.ModuleBase.Owner() 234 if owner == "" { 235 if Bool(module.sdkLibraryProperties.Core_lib) { 236 owner = "core" 237 } else { 238 owner = "android" 239 } 240 } 241 // Create dist rules to install the stubs libs to the dist dir 242 if len(module.publicApiStubsPath) == 1 { 243 fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+ 244 module.publicApiStubsImplPath.Strings()[0]+ 245 ":"+path.Join("apistubs", owner, "public", 246 module.BaseModuleName()+".jar")+")") 247 } 248 if len(module.systemApiStubsPath) == 1 { 249 fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+ 250 module.systemApiStubsImplPath.Strings()[0]+ 251 ":"+path.Join("apistubs", owner, "system", 252 module.BaseModuleName()+".jar")+")") 253 } 254 if len(module.testApiStubsPath) == 1 { 255 fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+ 256 module.testApiStubsImplPath.Strings()[0]+ 257 ":"+path.Join("apistubs", owner, "test", 258 module.BaseModuleName()+".jar")+")") 259 } 260 if module.publicApiFilePath != nil { 261 fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+ 262 module.publicApiFilePath.String()+ 263 ":"+path.Join("apistubs", owner, "public", "api", 264 module.BaseModuleName()+".txt")+")") 265 } 266 if module.systemApiFilePath != nil { 267 fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+ 268 module.systemApiFilePath.String()+ 269 ":"+path.Join("apistubs", owner, "system", "api", 270 module.BaseModuleName()+".txt")+")") 271 } 272 if module.testApiFilePath != nil { 273 fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+ 274 module.testApiFilePath.String()+ 275 ":"+path.Join("apistubs", owner, "test", "api", 276 module.BaseModuleName()+".txt")+")") 277 } 278 } 279 } 280 return data 281} 282 283// Module name of the stubs library 284func (module *SdkLibrary) stubsName(apiScope apiScope) string { 285 stubsName := module.BaseModuleName() + sdkStubsLibrarySuffix 286 switch apiScope { 287 case apiScopeSystem: 288 stubsName = stubsName + sdkSystemApiSuffix 289 case apiScopeTest: 290 stubsName = stubsName + sdkTestApiSuffix 291 } 292 return stubsName 293} 294 295// Module name of the docs 296func (module *SdkLibrary) docsName(apiScope apiScope) string { 297 docsName := module.BaseModuleName() + sdkDocsSuffix 298 switch apiScope { 299 case apiScopeSystem: 300 docsName = docsName + sdkSystemApiSuffix 301 case apiScopeTest: 302 docsName = docsName + sdkTestApiSuffix 303 } 304 return docsName 305} 306 307// Module name of the runtime implementation library 308func (module *SdkLibrary) implName() string { 309 return module.BaseModuleName() 310} 311 312// File path to the runtime implementation library 313func (module *SdkLibrary) implPath() string { 314 partition := "system" 315 if module.SocSpecific() { 316 partition = "vendor" 317 } else if module.DeviceSpecific() { 318 partition = "odm" 319 } else if module.ProductSpecific() { 320 partition = "product" 321 } 322 return "/" + partition + "/framework/" + module.implName() + ".jar" 323} 324 325// Module name of the XML file for the lib 326func (module *SdkLibrary) xmlFileName() string { 327 return module.BaseModuleName() + sdkXmlFileSuffix 328} 329 330// SDK version that the stubs library is built against. Note that this is always 331// *current. Older stubs library built with a numberd SDK version is created from 332// the prebuilt jar. 333func (module *SdkLibrary) sdkVersion(apiScope apiScope) string { 334 switch apiScope { 335 case apiScopePublic: 336 return "current" 337 case apiScopeSystem: 338 return "system_current" 339 case apiScopeTest: 340 return "test_current" 341 default: 342 return "current" 343 } 344} 345 346// $(INTERNAL_PLATFORM_<apiTagName>_API_FILE) points to the generated 347// api file for the current source 348// TODO: remove this when apicheck is done in soong 349func (module *SdkLibrary) apiTagName(apiScope apiScope) string { 350 apiTagName := strings.Replace(strings.ToUpper(module.BaseModuleName()), ".", "_", -1) 351 switch apiScope { 352 case apiScopeSystem: 353 apiTagName = apiTagName + "_SYSTEM" 354 case apiScopeTest: 355 apiTagName = apiTagName + "_TEST" 356 } 357 return apiTagName 358} 359 360func (module *SdkLibrary) latestApiFilegroupName(apiScope apiScope) string { 361 name := ":" + module.BaseModuleName() + ".api." 362 switch apiScope { 363 case apiScopePublic: 364 name = name + "public" 365 case apiScopeSystem: 366 name = name + "system" 367 case apiScopeTest: 368 name = name + "test" 369 } 370 name = name + ".latest" 371 return name 372} 373 374func (module *SdkLibrary) latestRemovedApiFilegroupName(apiScope apiScope) string { 375 name := ":" + module.BaseModuleName() + "-removed.api." 376 switch apiScope { 377 case apiScopePublic: 378 name = name + "public" 379 case apiScopeSystem: 380 name = name + "system" 381 case apiScopeTest: 382 name = name + "test" 383 } 384 name = name + ".latest" 385 return name 386} 387 388// Creates a static java library that has API stubs 389func (module *SdkLibrary) createStubsLibrary(mctx android.TopDownMutatorContext, apiScope apiScope) { 390 props := struct { 391 Name *string 392 Srcs []string 393 Sdk_version *string 394 Libs []string 395 Soc_specific *bool 396 Device_specific *bool 397 Product_specific *bool 398 Compile_dex *bool 399 No_standard_libs *bool 400 System_modules *string 401 Java_version *string 402 Product_variables struct { 403 Unbundled_build struct { 404 Enabled *bool 405 } 406 Pdk struct { 407 Enabled *bool 408 } 409 } 410 Openjdk9 struct { 411 Srcs []string 412 Javacflags []string 413 } 414 }{} 415 416 props.Name = proptools.StringPtr(module.stubsName(apiScope)) 417 // sources are generated from the droiddoc 418 props.Srcs = []string{":" + module.docsName(apiScope)} 419 props.Sdk_version = proptools.StringPtr(module.sdkVersion(apiScope)) 420 props.Libs = module.sdkLibraryProperties.Stub_only_libs 421 // Unbundled apps will use the prebult one from /prebuilts/sdk 422 if mctx.Config().UnbundledBuildUsePrebuiltSdks() { 423 props.Product_variables.Unbundled_build.Enabled = proptools.BoolPtr(false) 424 } 425 props.Product_variables.Pdk.Enabled = proptools.BoolPtr(false) 426 props.No_standard_libs = module.Library.Module.properties.No_standard_libs 427 props.System_modules = module.Library.Module.deviceProperties.System_modules 428 props.Openjdk9.Srcs = module.Library.Module.properties.Openjdk9.Srcs 429 props.Openjdk9.Javacflags = module.Library.Module.properties.Openjdk9.Javacflags 430 props.Java_version = module.Library.Module.properties.Java_version 431 if module.Library.Module.deviceProperties.Compile_dex != nil { 432 props.Compile_dex = module.Library.Module.deviceProperties.Compile_dex 433 } 434 435 if module.SocSpecific() { 436 props.Soc_specific = proptools.BoolPtr(true) 437 } else if module.DeviceSpecific() { 438 props.Device_specific = proptools.BoolPtr(true) 439 } else if module.ProductSpecific() { 440 props.Product_specific = proptools.BoolPtr(true) 441 } 442 443 mctx.CreateModule(android.ModuleFactoryAdaptor(LibraryFactory), &props) 444} 445 446// Creates a droiddoc module that creates stubs source files from the given full source 447// files 448func (module *SdkLibrary) createDocs(mctx android.TopDownMutatorContext, apiScope apiScope) { 449 props := struct { 450 Name *string 451 Srcs []string 452 Installable *bool 453 Srcs_lib *string 454 Srcs_lib_whitelist_dirs []string 455 Srcs_lib_whitelist_pkgs []string 456 Libs []string 457 Arg_files []string 458 Args *string 459 Api_tag_name *string 460 Api_filename *string 461 Removed_api_filename *string 462 No_standard_libs *bool 463 Java_version *string 464 Merge_annotations_dirs []string 465 Merge_inclusion_annotations_dirs []string 466 Check_api struct { 467 Current ApiToCheck 468 Last_released ApiToCheck 469 Ignore_missing_latest_api *bool 470 } 471 Aidl struct { 472 Include_dirs []string 473 Local_include_dirs []string 474 } 475 }{} 476 477 props.Name = proptools.StringPtr(module.docsName(apiScope)) 478 props.Srcs = append(props.Srcs, module.Library.Module.properties.Srcs...) 479 props.Srcs = append(props.Srcs, module.sdkLibraryProperties.Api_srcs...) 480 props.Installable = proptools.BoolPtr(false) 481 // A droiddoc module has only one Libs property and doesn't distinguish between 482 // shared libs and static libs. So we need to add both of these libs to Libs property. 483 props.Libs = module.Library.Module.properties.Libs 484 props.Libs = append(props.Libs, module.Library.Module.properties.Static_libs...) 485 props.Aidl.Include_dirs = module.Library.Module.deviceProperties.Aidl.Include_dirs 486 props.Aidl.Local_include_dirs = module.Library.Module.deviceProperties.Aidl.Local_include_dirs 487 props.No_standard_libs = module.Library.Module.properties.No_standard_libs 488 props.Java_version = module.Library.Module.properties.Java_version 489 490 props.Merge_annotations_dirs = module.sdkLibraryProperties.Merge_annotations_dirs 491 props.Merge_inclusion_annotations_dirs = module.sdkLibraryProperties.Merge_inclusion_annotations_dirs 492 493 droiddocArgs := " --stub-packages " + strings.Join(module.sdkLibraryProperties.Api_packages, ":") + 494 " " + android.JoinWithPrefix(module.sdkLibraryProperties.Hidden_api_packages, " --hide-package ") + 495 " " + android.JoinWithPrefix(module.sdkLibraryProperties.Droiddoc_options, " ") + 496 " --hide MissingPermission --hide BroadcastBehavior " + 497 "--hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol " + 498 "--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo" 499 500 switch apiScope { 501 case apiScopeSystem: 502 droiddocArgs = droiddocArgs + " -showAnnotation android.annotation.SystemApi" 503 case apiScopeTest: 504 droiddocArgs = droiddocArgs + " -showAnnotation android.annotation.TestApi" 505 } 506 props.Arg_files = module.sdkLibraryProperties.Droiddoc_option_files 507 props.Args = proptools.StringPtr(droiddocArgs) 508 509 // List of APIs identified from the provided source files are created. They are later 510 // compared against to the not-yet-released (a.k.a current) list of APIs and to the 511 // last-released (a.k.a numbered) list of API. 512 currentApiFileName := "current.txt" 513 removedApiFileName := "removed.txt" 514 switch apiScope { 515 case apiScopeSystem: 516 currentApiFileName = "system-" + currentApiFileName 517 removedApiFileName = "system-" + removedApiFileName 518 case apiScopeTest: 519 currentApiFileName = "test-" + currentApiFileName 520 removedApiFileName = "test-" + removedApiFileName 521 } 522 currentApiFileName = path.Join("api", currentApiFileName) 523 removedApiFileName = path.Join("api", removedApiFileName) 524 // TODO(jiyong): remove these three props 525 props.Api_tag_name = proptools.StringPtr(module.apiTagName(apiScope)) 526 props.Api_filename = proptools.StringPtr(currentApiFileName) 527 props.Removed_api_filename = proptools.StringPtr(removedApiFileName) 528 529 // check against the not-yet-release API 530 props.Check_api.Current.Api_file = proptools.StringPtr(currentApiFileName) 531 props.Check_api.Current.Removed_api_file = proptools.StringPtr(removedApiFileName) 532 533 // check against the latest released API 534 props.Check_api.Last_released.Api_file = proptools.StringPtr( 535 module.latestApiFilegroupName(apiScope)) 536 props.Check_api.Last_released.Removed_api_file = proptools.StringPtr( 537 module.latestRemovedApiFilegroupName(apiScope)) 538 props.Check_api.Ignore_missing_latest_api = proptools.BoolPtr(true) 539 props.Srcs_lib = module.sdkLibraryProperties.Srcs_lib 540 props.Srcs_lib_whitelist_dirs = module.sdkLibraryProperties.Srcs_lib_whitelist_dirs 541 props.Srcs_lib_whitelist_pkgs = module.sdkLibraryProperties.Srcs_lib_whitelist_pkgs 542 543 mctx.CreateModule(android.ModuleFactoryAdaptor(DroidstubsFactory), &props) 544} 545 546// Creates the xml file that publicizes the runtime library 547func (module *SdkLibrary) createXmlFile(mctx android.TopDownMutatorContext) { 548 template := ` 549<?xml version="1.0" encoding="utf-8"?> 550<!-- Copyright (C) 2018 The Android Open Source Project 551 552 Licensed under the Apache License, Version 2.0 (the "License"); 553 you may not use this file except in compliance with the License. 554 You may obtain a copy of the License at 555 556 http://www.apache.org/licenses/LICENSE-2.0 557 558 Unless required by applicable law or agreed to in writing, software 559 distributed under the License is distributed on an "AS IS" BASIS, 560 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 561 See the License for the specific language governing permissions and 562 limitations under the License. 563--> 564 565<permissions> 566 <library name="%s" file="%s"/> 567</permissions> 568` 569 // genrule to generate the xml file content from the template above 570 // TODO: preserve newlines in the generate xml file. Newlines are being squashed 571 // in the ninja file. Do we need to have an external tool for this? 572 xmlContent := fmt.Sprintf(template, module.BaseModuleName(), module.implPath()) 573 genruleProps := struct { 574 Name *string 575 Cmd *string 576 Out []string 577 }{} 578 genruleProps.Name = proptools.StringPtr(module.xmlFileName() + "-gen") 579 genruleProps.Cmd = proptools.StringPtr("echo '" + xmlContent + "' > $(out)") 580 genruleProps.Out = []string{module.xmlFileName()} 581 mctx.CreateModule(android.ModuleFactoryAdaptor(genrule.GenRuleFactory), &genruleProps) 582 583 // creates a prebuilt_etc module to actually place the xml file under 584 // <partition>/etc/permissions 585 etcProps := struct { 586 Name *string 587 Src *string 588 Sub_dir *string 589 Soc_specific *bool 590 Device_specific *bool 591 Product_specific *bool 592 }{} 593 etcProps.Name = proptools.StringPtr(module.xmlFileName()) 594 etcProps.Src = proptools.StringPtr(":" + module.xmlFileName() + "-gen") 595 etcProps.Sub_dir = proptools.StringPtr("permissions") 596 if module.SocSpecific() { 597 etcProps.Soc_specific = proptools.BoolPtr(true) 598 } else if module.DeviceSpecific() { 599 etcProps.Device_specific = proptools.BoolPtr(true) 600 } else if module.ProductSpecific() { 601 etcProps.Product_specific = proptools.BoolPtr(true) 602 } 603 mctx.CreateModule(android.ModuleFactoryAdaptor(android.PrebuiltEtcFactory), &etcProps) 604} 605 606func (module *SdkLibrary) PrebuiltJars(ctx android.BaseContext, sdkVersion string) android.Paths { 607 var api, v string 608 if sdkVersion == "" { 609 api = "system" 610 v = "current" 611 } else if strings.Contains(sdkVersion, "_") { 612 t := strings.Split(sdkVersion, "_") 613 api = t[0] 614 v = t[1] 615 } else { 616 api = "public" 617 v = sdkVersion 618 } 619 dir := filepath.Join("prebuilts", "sdk", v, api) 620 jar := filepath.Join(dir, module.BaseModuleName()+".jar") 621 jarPath := android.ExistentPathForSource(ctx, jar) 622 if !jarPath.Valid() { 623 ctx.PropertyErrorf("sdk_library", "invalid sdk version %q, %q does not exist", v, jar) 624 return nil 625 } 626 return android.Paths{jarPath.Path()} 627} 628 629// to satisfy SdkLibraryDependency interface 630func (module *SdkLibrary) SdkHeaderJars(ctx android.BaseContext, sdkVersion string) android.Paths { 631 // This module is just a wrapper for the stubs. 632 if ctx.Config().UnbundledBuildUsePrebuiltSdks() { 633 return module.PrebuiltJars(ctx, sdkVersion) 634 } else { 635 if strings.HasPrefix(sdkVersion, "system_") { 636 return module.systemApiStubsPath 637 } else if sdkVersion == "" { 638 return module.Library.HeaderJars() 639 } else { 640 return module.publicApiStubsPath 641 } 642 } 643} 644 645// to satisfy SdkLibraryDependency interface 646func (module *SdkLibrary) SdkImplementationJars(ctx android.BaseContext, sdkVersion string) android.Paths { 647 // This module is just a wrapper for the stubs. 648 if ctx.Config().UnbundledBuildUsePrebuiltSdks() { 649 return module.PrebuiltJars(ctx, sdkVersion) 650 } else { 651 if strings.HasPrefix(sdkVersion, "system_") { 652 return module.systemApiStubsImplPath 653 } else if sdkVersion == "" { 654 return module.Library.ImplementationJars() 655 } else { 656 return module.publicApiStubsImplPath 657 } 658 } 659} 660 661func (module *SdkLibrary) SetNoDist() { 662 module.sdkLibraryProperties.No_dist = proptools.BoolPtr(true) 663} 664 665var javaSdkLibrariesKey = android.NewOnceKey("javaSdkLibraries") 666 667func javaSdkLibraries(config android.Config) *[]string { 668 return config.Once(javaSdkLibrariesKey, func() interface{} { 669 return &[]string{} 670 }).(*[]string) 671} 672 673// For a java_sdk_library module, create internal modules for stubs, docs, 674// runtime libs and xml file. If requested, the stubs and docs are created twice 675// once for public API level and once for system API level 676func SdkLibraryMutator(mctx android.TopDownMutatorContext) { 677 if module, ok := mctx.Module().(*SdkLibrary); ok { 678 module.createInternalModules(mctx) 679 } else if module, ok := mctx.Module().(syspropLibraryInterface); ok { 680 module.SyspropJavaModule().createInternalModules(mctx) 681 } 682} 683 684func (module *SdkLibrary) createInternalModules(mctx android.TopDownMutatorContext) { 685 if len(module.Library.Module.properties.Srcs) == 0 { 686 mctx.PropertyErrorf("srcs", "java_sdk_library must specify srcs") 687 } 688 689 if len(module.sdkLibraryProperties.Api_packages) == 0 { 690 mctx.PropertyErrorf("api_packages", "java_sdk_library must specify api_packages") 691 } 692 693 missing_current_api := false 694 695 for _, scope := range []string{"", "system-", "test-"} { 696 for _, api := range []string{"current.txt", "removed.txt"} { 697 path := path.Join(mctx.ModuleDir(), "api", scope+api) 698 p := android.ExistentPathForSource(mctx, path) 699 if !p.Valid() { 700 mctx.ModuleErrorf("Current api file %#v doesn't exist", path) 701 missing_current_api = true 702 } 703 } 704 } 705 706 if missing_current_api { 707 script := "build/soong/scripts/gen-java-current-api-files.sh" 708 p := android.ExistentPathForSource(mctx, script) 709 710 if !p.Valid() { 711 panic(fmt.Sprintf("script file %s doesn't exist", script)) 712 } 713 714 mctx.ModuleErrorf("One or more current api files are missing. "+ 715 "You can update them by:\n"+ 716 "%s %q && m update-api", script, mctx.ModuleDir()) 717 return 718 } 719 720 // for public API stubs 721 module.createStubsLibrary(mctx, apiScopePublic) 722 module.createDocs(mctx, apiScopePublic) 723 724 if !Bool(module.properties.No_standard_libs) { 725 // for system API stubs 726 module.createStubsLibrary(mctx, apiScopeSystem) 727 module.createDocs(mctx, apiScopeSystem) 728 729 // for test API stubs 730 module.createStubsLibrary(mctx, apiScopeTest) 731 module.createDocs(mctx, apiScopeTest) 732 733 // for runtime 734 module.createXmlFile(mctx) 735 } 736 737 // record java_sdk_library modules so that they are exported to make 738 javaSdkLibraries := javaSdkLibraries(mctx.Config()) 739 javaSdkLibrariesLock.Lock() 740 defer javaSdkLibrariesLock.Unlock() 741 *javaSdkLibraries = append(*javaSdkLibraries, module.BaseModuleName()) 742} 743 744func (module *SdkLibrary) InitSdkLibraryProperties() { 745 module.AddProperties( 746 &module.sdkLibraryProperties, 747 &module.Library.Module.properties, 748 &module.Library.Module.dexpreoptProperties, 749 &module.Library.Module.deviceProperties, 750 &module.Library.Module.protoProperties, 751 ) 752 753 module.Library.Module.properties.Installable = proptools.BoolPtr(true) 754 module.Library.Module.deviceProperties.IsSDKLibrary = true 755} 756 757func SdkLibraryFactory() android.Module { 758 module := &SdkLibrary{} 759 module.InitSdkLibraryProperties() 760 InitJavaModule(module, android.HostAndDeviceSupported) 761 return module 762} 763