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 android 16 17import ( 18 "fmt" 19 "sort" 20 "strconv" 21 "strings" 22 "sync" 23 24 "github.com/google/blueprint" 25) 26 27const ( 28 SdkVersion_Android10 = 29 29) 30 31type ApexInfo struct { 32 // Name of the apex variant that this module is mutated into 33 ApexName string 34 35 MinSdkVersion int 36 Updatable bool 37} 38 39// Extracted from ApexModule to make it easier to define custom subsets of the 40// ApexModule interface and improve code navigation within the IDE. 41type DepIsInSameApex interface { 42 // DepIsInSameApex tests if the other module 'dep' is installed to the same 43 // APEX as this module 44 DepIsInSameApex(ctx BaseModuleContext, dep Module) bool 45} 46 47// ApexModule is the interface that a module type is expected to implement if 48// the module has to be built differently depending on whether the module 49// is destined for an apex or not (installed to one of the regular partitions). 50// 51// Native shared libraries are one such module type; when it is built for an 52// APEX, it should depend only on stable interfaces such as NDK, stable AIDL, 53// or C APIs from other APEXs. 54// 55// A module implementing this interface will be mutated into multiple 56// variations by apex.apexMutator if it is directly or indirectly included 57// in one or more APEXs. Specifically, if a module is included in apex.foo and 58// apex.bar then three apex variants are created: platform, apex.foo and 59// apex.bar. The platform variant is for the regular partitions 60// (e.g., /system or /vendor, etc.) while the other two are for the APEXs, 61// respectively. 62type ApexModule interface { 63 Module 64 DepIsInSameApex 65 66 apexModuleBase() *ApexModuleBase 67 68 // Marks that this module should be built for the specified APEX. 69 // Call this before apex.apexMutator is run. 70 BuildForApex(apex ApexInfo) 71 72 // Returns the APEXes that this module will be built for 73 ApexVariations() []ApexInfo 74 75 // Returns the name of APEX that this module will be built for. Empty string 76 // is returned when 'IsForPlatform() == true'. Note that a module can be 77 // included in multiple APEXes, in which case, the module is mutated into 78 // multiple modules each of which for an APEX. This method returns the 79 // name of the APEX that a variant module is for. 80 // Call this after apex.apexMutator is run. 81 ApexName() string 82 83 // Tests whether this module will be built for the platform or not. 84 // This is a shortcut for ApexName() == "" 85 IsForPlatform() bool 86 87 // Tests if this module could have APEX variants. APEX variants are 88 // created only for the modules that returns true here. This is useful 89 // for not creating APEX variants for certain types of shared libraries 90 // such as NDK stubs. 91 CanHaveApexVariants() bool 92 93 // Tests if this module can be installed to APEX as a file. For example, 94 // this would return true for shared libs while return false for static 95 // libs. 96 IsInstallableToApex() bool 97 98 // Mutate this module into one or more variants each of which is built 99 // for an APEX marked via BuildForApex(). 100 CreateApexVariations(mctx BottomUpMutatorContext) []Module 101 102 // Tests if this module is available for the specified APEX or ":platform" 103 AvailableFor(what string) bool 104 105 // Return true if this module is not available to platform (i.e. apex_available 106 // property doesn't have "//apex_available:platform"), or shouldn't be available 107 // to platform, which is the case when this module depends on other module that 108 // isn't available to platform. 109 NotAvailableForPlatform() bool 110 111 // Mark that this module is not available to platform. Set by the 112 // check-platform-availability mutator in the apex package. 113 SetNotAvailableForPlatform() 114 115 // Returns the highest version which is <= maxSdkVersion. 116 // For example, with maxSdkVersion is 10 and versionList is [9,11] 117 // it returns 9 as string 118 ChooseSdkVersion(versionList []string, maxSdkVersion int) (string, error) 119 120 // Tests if the module comes from an updatable APEX. 121 Updatable() bool 122 123 // List of APEXes that this module tests. The module has access to 124 // the private part of the listed APEXes even when it is not included in the 125 // APEXes. 126 TestFor() []string 127 128 // Returns nil if this module supports sdkVersion 129 // Otherwise, returns error with reason 130 ShouldSupportSdkVersion(ctx BaseModuleContext, sdkVersion int) error 131} 132 133type ApexProperties struct { 134 // Availability of this module in APEXes. Only the listed APEXes can contain 135 // this module. If the module has stubs then other APEXes and the platform may 136 // access it through them (subject to visibility). 137 // 138 // "//apex_available:anyapex" is a pseudo APEX name that matches to any APEX. 139 // "//apex_available:platform" refers to non-APEX partitions like "system.img". 140 // Default is ["//apex_available:platform"]. 141 Apex_available []string 142 143 Info ApexInfo `blueprint:"mutated"` 144 145 NotAvailableForPlatform bool `blueprint:"mutated"` 146} 147 148// Marker interface that identifies dependencies that are excluded from APEX 149// contents. 150type ExcludeFromApexContentsTag interface { 151 blueprint.DependencyTag 152 153 // Method that differentiates this interface from others. 154 ExcludeFromApexContents() 155} 156 157// Provides default implementation for the ApexModule interface. APEX-aware 158// modules are expected to include this struct and call InitApexModule(). 159type ApexModuleBase struct { 160 ApexProperties ApexProperties 161 162 canHaveApexVariants bool 163 164 apexVariationsLock sync.Mutex // protects apexVariations during parallel apexDepsMutator 165 apexVariations []ApexInfo 166} 167 168func (m *ApexModuleBase) apexModuleBase() *ApexModuleBase { 169 return m 170} 171 172func (m *ApexModuleBase) ApexAvailable() []string { 173 return m.ApexProperties.Apex_available 174} 175 176func (m *ApexModuleBase) TestFor() []string { 177 // To be implemented by concrete types inheriting ApexModuleBase 178 return nil 179} 180 181func (m *ApexModuleBase) BuildForApex(apex ApexInfo) { 182 m.apexVariationsLock.Lock() 183 defer m.apexVariationsLock.Unlock() 184 for _, v := range m.apexVariations { 185 if v.ApexName == apex.ApexName { 186 return 187 } 188 } 189 m.apexVariations = append(m.apexVariations, apex) 190} 191 192func (m *ApexModuleBase) ApexVariations() []ApexInfo { 193 return m.apexVariations 194} 195 196func (m *ApexModuleBase) ApexName() string { 197 return m.ApexProperties.Info.ApexName 198} 199 200func (m *ApexModuleBase) IsForPlatform() bool { 201 return m.ApexProperties.Info.ApexName == "" 202} 203 204func (m *ApexModuleBase) CanHaveApexVariants() bool { 205 return m.canHaveApexVariants 206} 207 208func (m *ApexModuleBase) IsInstallableToApex() bool { 209 // should be overriden if needed 210 return false 211} 212 213const ( 214 AvailableToPlatform = "//apex_available:platform" 215 AvailableToAnyApex = "//apex_available:anyapex" 216) 217 218func CheckAvailableForApex(what string, apex_available []string) bool { 219 if len(apex_available) == 0 { 220 // apex_available defaults to ["//apex_available:platform"], 221 // which means 'available to the platform but no apexes'. 222 return what == AvailableToPlatform 223 } 224 return InList(what, apex_available) || 225 (what != AvailableToPlatform && InList(AvailableToAnyApex, apex_available)) 226} 227 228func (m *ApexModuleBase) AvailableFor(what string) bool { 229 return CheckAvailableForApex(what, m.ApexProperties.Apex_available) 230} 231 232func (m *ApexModuleBase) NotAvailableForPlatform() bool { 233 return m.ApexProperties.NotAvailableForPlatform 234} 235 236func (m *ApexModuleBase) SetNotAvailableForPlatform() { 237 m.ApexProperties.NotAvailableForPlatform = true 238} 239 240func (m *ApexModuleBase) DepIsInSameApex(ctx BaseModuleContext, dep Module) bool { 241 // By default, if there is a dependency from A to B, we try to include both in the same APEX, 242 // unless B is explicitly from outside of the APEX (i.e. a stubs lib). Thus, returning true. 243 // This is overridden by some module types like apex.ApexBundle, cc.Module, java.Module, etc. 244 return true 245} 246 247func (m *ApexModuleBase) ChooseSdkVersion(versionList []string, maxSdkVersion int) (string, error) { 248 for i := range versionList { 249 ver, _ := strconv.Atoi(versionList[len(versionList)-i-1]) 250 if ver <= maxSdkVersion { 251 return versionList[len(versionList)-i-1], nil 252 } 253 } 254 return "", fmt.Errorf("not found a version(<=%d) in versionList: %v", maxSdkVersion, versionList) 255} 256 257func (m *ApexModuleBase) checkApexAvailableProperty(mctx BaseModuleContext) { 258 for _, n := range m.ApexProperties.Apex_available { 259 if n == AvailableToPlatform || n == AvailableToAnyApex { 260 continue 261 } 262 if !mctx.OtherModuleExists(n) && !mctx.Config().AllowMissingDependencies() { 263 mctx.PropertyErrorf("apex_available", "%q is not a valid module name", n) 264 } 265 } 266} 267 268func (m *ApexModuleBase) Updatable() bool { 269 return m.ApexProperties.Info.Updatable 270} 271 272type byApexName []ApexInfo 273 274func (a byApexName) Len() int { return len(a) } 275func (a byApexName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 276func (a byApexName) Less(i, j int) bool { return a[i].ApexName < a[j].ApexName } 277 278func (m *ApexModuleBase) CreateApexVariations(mctx BottomUpMutatorContext) []Module { 279 if len(m.apexVariations) > 0 { 280 m.checkApexAvailableProperty(mctx) 281 282 sort.Sort(byApexName(m.apexVariations)) 283 variations := []string{} 284 variations = append(variations, "") // Original variation for platform 285 for _, apex := range m.apexVariations { 286 variations = append(variations, apex.ApexName) 287 } 288 289 defaultVariation := "" 290 mctx.SetDefaultDependencyVariation(&defaultVariation) 291 292 modules := mctx.CreateVariations(variations...) 293 for i, mod := range modules { 294 platformVariation := i == 0 295 if platformVariation && !mctx.Host() && !mod.(ApexModule).AvailableFor(AvailableToPlatform) { 296 mod.SkipInstall() 297 } 298 if !platformVariation { 299 mod.(ApexModule).apexModuleBase().ApexProperties.Info = m.apexVariations[i-1] 300 } 301 } 302 return modules 303 } 304 return nil 305} 306 307var apexData OncePer 308var apexNamesMapMutex sync.Mutex 309var apexNamesKey = NewOnceKey("apexNames") 310 311// This structure maintains the global mapping in between modules and APEXes. 312// Examples: 313// 314// apexNamesMap()["foo"]["bar"] == true: module foo is directly depended on by APEX bar 315// apexNamesMap()["foo"]["bar"] == false: module foo is indirectly depended on by APEX bar 316// apexNamesMap()["foo"]["bar"] doesn't exist: foo is not built for APEX bar 317func apexNamesMap() map[string]map[string]bool { 318 return apexData.Once(apexNamesKey, func() interface{} { 319 return make(map[string]map[string]bool) 320 }).(map[string]map[string]bool) 321} 322 323// Update the map to mark that a module named moduleName is directly or indirectly 324// depended on by the specified APEXes. Directly depending means that a module 325// is explicitly listed in the build definition of the APEX via properties like 326// native_shared_libs, java_libs, etc. 327func UpdateApexDependency(apex ApexInfo, moduleName string, directDep bool) { 328 apexNamesMapMutex.Lock() 329 defer apexNamesMapMutex.Unlock() 330 apexesForModule, ok := apexNamesMap()[moduleName] 331 if !ok { 332 apexesForModule = make(map[string]bool) 333 apexNamesMap()[moduleName] = apexesForModule 334 } 335 apexesForModule[apex.ApexName] = apexesForModule[apex.ApexName] || directDep 336} 337 338// TODO(b/146393795): remove this when b/146393795 is fixed 339func ClearApexDependency() { 340 m := apexNamesMap() 341 for k := range m { 342 delete(m, k) 343 } 344} 345 346// Tests whether a module named moduleName is directly depended on by an APEX 347// named apexName. 348func DirectlyInApex(apexName string, moduleName string) bool { 349 apexNamesMapMutex.Lock() 350 defer apexNamesMapMutex.Unlock() 351 if apexNames, ok := apexNamesMap()[moduleName]; ok { 352 return apexNames[apexName] 353 } 354 return false 355} 356 357type hostContext interface { 358 Host() bool 359} 360 361// Tests whether a module named moduleName is directly depended on by any APEX. 362func DirectlyInAnyApex(ctx hostContext, moduleName string) bool { 363 if ctx.Host() { 364 // Host has no APEX. 365 return false 366 } 367 apexNamesMapMutex.Lock() 368 defer apexNamesMapMutex.Unlock() 369 if apexNames, ok := apexNamesMap()[moduleName]; ok { 370 for an := range apexNames { 371 if apexNames[an] { 372 return true 373 } 374 } 375 } 376 return false 377} 378 379// Tests whether a module named module is depended on (including both 380// direct and indirect dependencies) by any APEX. 381func InAnyApex(moduleName string) bool { 382 apexNamesMapMutex.Lock() 383 defer apexNamesMapMutex.Unlock() 384 apexNames, ok := apexNamesMap()[moduleName] 385 return ok && len(apexNames) > 0 386} 387 388func GetApexesForModule(moduleName string) []string { 389 ret := []string{} 390 apexNamesMapMutex.Lock() 391 defer apexNamesMapMutex.Unlock() 392 if apexNames, ok := apexNamesMap()[moduleName]; ok { 393 for an := range apexNames { 394 ret = append(ret, an) 395 } 396 } 397 return ret 398} 399 400func InitApexModule(m ApexModule) { 401 base := m.apexModuleBase() 402 base.canHaveApexVariants = true 403 404 m.AddProperties(&base.ApexProperties) 405} 406 407// A dependency info for a single ApexModule, either direct or transitive. 408type ApexModuleDepInfo struct { 409 // Name of the dependency 410 To string 411 // List of dependencies To belongs to. Includes APEX itself, if a direct dependency. 412 From []string 413 // Whether the dependency belongs to the final compiled APEX. 414 IsExternal bool 415 // min_sdk_version of the ApexModule 416 MinSdkVersion string 417} 418 419// A map of a dependency name to its ApexModuleDepInfo 420type DepNameToDepInfoMap map[string]ApexModuleDepInfo 421 422type ApexBundleDepsInfo struct { 423 flatListPath OutputPath 424 fullListPath OutputPath 425} 426 427type ApexBundleDepsInfoIntf interface { 428 Updatable() bool 429 FlatListPath() Path 430 FullListPath() Path 431} 432 433func (d *ApexBundleDepsInfo) FlatListPath() Path { 434 return d.flatListPath 435} 436 437func (d *ApexBundleDepsInfo) FullListPath() Path { 438 return d.fullListPath 439} 440 441// Generate two module out files: 442// 1. FullList with transitive deps and their parents in the dep graph 443// 2. FlatList with a flat list of transitive deps 444func (d *ApexBundleDepsInfo) BuildDepsInfoLists(ctx ModuleContext, minSdkVersion string, depInfos DepNameToDepInfoMap) { 445 var fullContent strings.Builder 446 var flatContent strings.Builder 447 448 fmt.Fprintf(&flatContent, "%s(minSdkVersion:%s):\\n", ctx.ModuleName(), minSdkVersion) 449 for _, key := range FirstUniqueStrings(SortedStringKeys(depInfos)) { 450 info := depInfos[key] 451 toName := fmt.Sprintf("%s(minSdkVersion:%s)", info.To, info.MinSdkVersion) 452 if info.IsExternal { 453 toName = toName + " (external)" 454 } 455 fmt.Fprintf(&fullContent, "%s <- %s\\n", toName, strings.Join(SortedUniqueStrings(info.From), ", ")) 456 fmt.Fprintf(&flatContent, " %s\\n", toName) 457 } 458 459 d.fullListPath = PathForModuleOut(ctx, "depsinfo", "fulllist.txt").OutputPath 460 ctx.Build(pctx, BuildParams{ 461 Rule: WriteFile, 462 Description: "Full Dependency Info", 463 Output: d.fullListPath, 464 Args: map[string]string{ 465 "content": fullContent.String(), 466 }, 467 }) 468 469 d.flatListPath = PathForModuleOut(ctx, "depsinfo", "flatlist.txt").OutputPath 470 ctx.Build(pctx, BuildParams{ 471 Rule: WriteFile, 472 Description: "Flat Dependency Info", 473 Output: d.flatListPath, 474 Args: map[string]string{ 475 "content": flatContent.String(), 476 }, 477 }) 478} 479 480// TODO(b/158059172): remove minSdkVersion allowlist 481var minSdkVersionAllowlist = map[string]int{ 482 "adbd": 30, 483 "android.net.ipsec.ike": 30, 484 "androidx-constraintlayout_constraintlayout-solver": 30, 485 "androidx.annotation_annotation": 28, 486 "androidx.arch.core_core-common": 28, 487 "androidx.collection_collection": 28, 488 "androidx.lifecycle_lifecycle-common": 28, 489 "apache-commons-compress": 29, 490 "bouncycastle_ike_digests": 30, 491 "brotli-java": 29, 492 "captiveportal-lib": 28, 493 "flatbuffer_headers": 30, 494 "framework-permission": 30, 495 "framework-statsd": 30, 496 "gemmlowp_headers": 30, 497 "ike-internals": 30, 498 "kotlinx-coroutines-android": 28, 499 "kotlinx-coroutines-core": 28, 500 "libadb_crypto": 30, 501 "libadb_pairing_auth": 30, 502 "libadb_pairing_connection": 30, 503 "libadb_pairing_server": 30, 504 "libadb_protos": 30, 505 "libadb_tls_connection": 30, 506 "libadbconnection_client": 30, 507 "libadbconnection_server": 30, 508 "libadbd_core": 30, 509 "libadbd_services": 30, 510 "libadbd": 30, 511 "libapp_processes_protos_lite": 30, 512 "libasyncio": 30, 513 "libbrotli": 30, 514 "libbuildversion": 30, 515 "libcrypto_static": 30, 516 "libcrypto_utils": 30, 517 "libdiagnose_usb": 30, 518 "libeigen": 30, 519 "liblz4": 30, 520 "libmdnssd": 30, 521 "libneuralnetworks_common": 30, 522 "libneuralnetworks_headers": 30, 523 "libneuralnetworks": 30, 524 "libprocpartition": 30, 525 "libprotobuf-java-lite": 30, 526 "libprotoutil": 30, 527 "libqemu_pipe": 30, 528 "libstats_jni": 30, 529 "libstatslog_statsd": 30, 530 "libstatsmetadata": 30, 531 "libstatspull": 30, 532 "libstatssocket": 30, 533 "libsync": 30, 534 "libtextclassifier_hash_headers": 30, 535 "libtextclassifier_hash_static": 30, 536 "libtflite_kernel_utils": 30, 537 "libwatchdog": 29, 538 "libzstd": 30, 539 "metrics-constants-protos": 28, 540 "net-utils-framework-common": 29, 541 "permissioncontroller-statsd": 28, 542 "philox_random_headers": 30, 543 "philox_random": 30, 544 "service-permission": 30, 545 "service-statsd": 30, 546 "statsd-aidl-ndk_platform": 30, 547 "statsd": 30, 548 "tensorflow_headers": 30, 549 "xz-java": 29, 550} 551 552// Function called while walking an APEX's payload dependencies. 553// 554// Return true if the `to` module should be visited, false otherwise. 555type PayloadDepsCallback func(ctx ModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool 556 557// UpdatableModule represents updatable APEX/APK 558type UpdatableModule interface { 559 Module 560 WalkPayloadDeps(ctx ModuleContext, do PayloadDepsCallback) 561} 562 563// CheckMinSdkVersion checks if every dependency of an updatable module sets min_sdk_version accordingly 564func CheckMinSdkVersion(m UpdatableModule, ctx ModuleContext, minSdkVersion int) { 565 // do not enforce min_sdk_version for host 566 if ctx.Host() { 567 return 568 } 569 570 // do not enforce for coverage build 571 if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT") || ctx.DeviceConfig().NativeCoverageEnabled() || ctx.DeviceConfig().ClangCoverageEnabled() { 572 return 573 } 574 575 // do not enforce deps.min_sdk_version if APEX/APK doesn't set min_sdk_version or 576 // min_sdk_version is not finalized (e.g. current or codenames) 577 if minSdkVersion == FutureApiLevel { 578 return 579 } 580 581 m.WalkPayloadDeps(ctx, func(ctx ModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool { 582 if externalDep { 583 // external deps are outside the payload boundary, which is "stable" interface. 584 // We don't have to check min_sdk_version for external dependencies. 585 return false 586 } 587 if am, ok := from.(DepIsInSameApex); ok && !am.DepIsInSameApex(ctx, to) { 588 return false 589 } 590 if err := to.ShouldSupportSdkVersion(ctx, minSdkVersion); err != nil { 591 toName := ctx.OtherModuleName(to) 592 if ver, ok := minSdkVersionAllowlist[toName]; !ok || ver > minSdkVersion { 593 ctx.OtherModuleErrorf(to, "should support min_sdk_version(%v) for %q: %v. Dependency path: %s", 594 minSdkVersion, ctx.ModuleName(), err.Error(), ctx.GetPathString(false)) 595 return false 596 } 597 } 598 return true 599 }) 600} 601