1// Copyright 2016 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 cc 16 17import ( 18 "path/filepath" 19 "sort" 20 "strings" 21 22 "github.com/google/blueprint/proptools" 23 24 "android/soong/android" 25 "android/soong/cc/config" 26 "android/soong/fuzz" 27) 28 29func init() { 30 android.RegisterModuleType("cc_fuzz", LibFuzzFactory) 31 android.RegisterParallelSingletonType("cc_fuzz_packaging", fuzzPackagingFactory) 32 android.RegisterParallelSingletonType("cc_fuzz_presubmit_packaging", fuzzPackagingFactoryPresubmit) 33} 34 35type FuzzProperties struct { 36 FuzzFramework fuzz.Framework `blueprint:"mutated"` 37} 38 39type fuzzer struct { 40 Properties FuzzProperties 41} 42 43func (fuzzer *fuzzer) flags(ctx ModuleContext, flags Flags) Flags { 44 if fuzzer.Properties.FuzzFramework == fuzz.AFL { 45 flags.Local.CFlags = append(flags.Local.CFlags, []string{ 46 "-fsanitize-coverage=trace-pc-guard", 47 "-Wno-unused-result", 48 "-Wno-unused-parameter", 49 "-Wno-unused-function", 50 }...) 51 } 52 53 return flags 54} 55 56func (fuzzer *fuzzer) props() []interface{} { 57 return []interface{}{&fuzzer.Properties} 58} 59 60func fuzzMutatorDeps(mctx android.TopDownMutatorContext) { 61 currentModule, ok := mctx.Module().(*Module) 62 if !ok { 63 return 64 } 65 66 if currentModule.fuzzer == nil { 67 return 68 } 69 70 mctx.WalkDeps(func(child android.Module, parent android.Module) bool { 71 c, ok := child.(*Module) 72 if !ok { 73 return false 74 } 75 76 if c.sanitize == nil { 77 return false 78 } 79 80 isFuzzerPointer := c.sanitize.getSanitizerBoolPtr(Fuzzer) 81 if isFuzzerPointer == nil || !*isFuzzerPointer { 82 return false 83 } 84 85 if c.fuzzer == nil { 86 return false 87 } 88 89 c.fuzzer.Properties.FuzzFramework = currentModule.fuzzer.Properties.FuzzFramework 90 return true 91 }) 92} 93 94// cc_fuzz creates a host/device fuzzer binary. Host binaries can be found at 95// $ANDROID_HOST_OUT/fuzz/, and device binaries can be found at /data/fuzz on 96// your device, or $ANDROID_PRODUCT_OUT/data/fuzz in your build tree. 97func LibFuzzFactory() android.Module { 98 module := NewFuzzer(android.HostAndDeviceSupported) 99 module.testModule = true 100 return module.Init() 101} 102 103type fuzzBinary struct { 104 *binaryDecorator 105 *baseCompiler 106 fuzzPackagedModule fuzz.FuzzPackagedModule 107 installedSharedDeps []string 108 sharedLibraries android.RuleBuilderInstalls 109 data []android.DataPath 110} 111 112func (fuzz *fuzzBinary) fuzzBinary() bool { 113 return true 114} 115 116func (fuzz *fuzzBinary) linkerProps() []interface{} { 117 props := fuzz.binaryDecorator.linkerProps() 118 props = append(props, &fuzz.fuzzPackagedModule.FuzzProperties) 119 120 return props 121} 122 123func (fuzz *fuzzBinary) linkerInit(ctx BaseModuleContext) { 124 fuzz.binaryDecorator.linkerInit(ctx) 125} 126 127func (fuzzBin *fuzzBinary) linkerDeps(ctx DepsContext, deps Deps) Deps { 128 if ctx.Config().Getenv("FUZZ_FRAMEWORK") == "AFL" { 129 deps.HeaderLibs = append(deps.HeaderLibs, "libafl_headers") 130 } else { 131 deps.StaticLibs = append(deps.StaticLibs, config.LibFuzzerRuntimeLibrary()) 132 // Fuzzers built with HWASAN should use the interceptors for better 133 // mutation based on signals in strcmp, memcpy, etc. This is only needed for 134 // fuzz targets, not generic HWASAN-ified binaries or libraries. 135 if module, ok := ctx.Module().(*Module); ok { 136 if module.IsSanitizerEnabled(Hwasan) { 137 deps.StaticLibs = append(deps.StaticLibs, config.LibFuzzerRuntimeInterceptors()) 138 } 139 } 140 } 141 142 deps = fuzzBin.binaryDecorator.linkerDeps(ctx, deps) 143 return deps 144} 145 146func (fuzz *fuzzBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags { 147 subdir := "lib" 148 if ctx.inVendor() { 149 subdir = "lib/vendor" 150 } 151 152 flags = fuzz.binaryDecorator.linkerFlags(ctx, flags) 153 // RunPaths on devices isn't instantiated by the base linker. `../lib` for 154 // installed fuzz targets (both host and device), and `./lib` for fuzz 155 // target packages. 156 flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/`+subdir) 157 158 // When running on device, fuzz targets with vendor: true set will be in 159 // fuzzer_name/vendor/fuzzer_name (note the extra 'vendor' and thus need to 160 // link with libraries in ../../lib/. Non-vendor binaries only need to look 161 // one level up, in ../lib/. 162 if ctx.inVendor() { 163 flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/../../`+subdir) 164 } else { 165 flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/../`+subdir) 166 } 167 168 return flags 169} 170 171func (fuzz *fuzzBinary) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) { 172 fuzz.binaryDecorator.moduleInfoJSON(ctx, moduleInfoJSON) 173 moduleInfoJSON.Class = []string{"EXECUTABLES"} 174} 175 176// IsValidSharedDependency takes a module and determines if it is a unique shared library 177// that should be installed in the fuzz target output directories. This function 178// returns true, unless: 179// - The module is not an installable shared library, or 180// - The module is a header or stub, or 181// - The module is a prebuilt and its source is available, or 182// - The module is a versioned member of an SDK snapshot. 183func IsValidSharedDependency(dependency android.Module) bool { 184 // TODO(b/144090547): We should be parsing these modules using 185 // ModuleDependencyTag instead of the current brute-force checking. 186 187 linkable, ok := dependency.(LinkableInterface) 188 if !ok || !linkable.CcLibraryInterface() { 189 // Discard non-linkables. 190 return false 191 } 192 193 if !linkable.Shared() { 194 // Discard static libs. 195 return false 196 } 197 198 if lib := moduleLibraryInterface(dependency); lib != nil && lib.buildStubs() && linkable.CcLibrary() { 199 // Discard stubs libs (only CCLibrary variants). Prebuilt libraries should not 200 // be excluded on the basis of they're not CCLibrary()'s. 201 return false 202 } 203 204 // We discarded module stubs libraries above, but the LLNDK prebuilts stubs 205 // libraries must be handled differently - by looking for the stubDecorator. 206 // Discard LLNDK prebuilts stubs as well. 207 if ccLibrary, isCcLibrary := dependency.(*Module); isCcLibrary { 208 if _, isLLndkStubLibrary := ccLibrary.linker.(*stubDecorator); isLLndkStubLibrary { 209 return false 210 } 211 // Discard installable:false libraries because they are expected to be absent 212 // in runtime. 213 if !proptools.BoolDefault(ccLibrary.Installable(), true) { 214 return false 215 } 216 } 217 218 // If the same library is present both as source and a prebuilt we must pick 219 // only one to avoid a conflict. Always prefer the source since the prebuilt 220 // probably won't be built with sanitizers enabled. 221 if prebuilt := android.GetEmbeddedPrebuilt(dependency); prebuilt != nil && prebuilt.SourceExists() { 222 return false 223 } 224 225 return true 226} 227 228func SharedLibraryInstallLocation( 229 libraryBase string, isHost bool, isVendor bool, fuzzDir string, archString string) string { 230 installLocation := "$(PRODUCT_OUT)/data" 231 if isHost { 232 installLocation = "$(HOST_OUT)" 233 } 234 subdir := "lib" 235 if isVendor { 236 subdir = "lib/vendor" 237 } 238 installLocation = filepath.Join( 239 installLocation, fuzzDir, archString, subdir, libraryBase) 240 return installLocation 241} 242 243// Get the device-only shared library symbols install directory. 244func SharedLibrarySymbolsInstallLocation(libraryBase string, isVendor bool, fuzzDir string, archString string) string { 245 subdir := "lib" 246 if isVendor { 247 subdir = "lib/vendor" 248 } 249 return filepath.Join("$(PRODUCT_OUT)/symbols/data/", fuzzDir, archString, subdir, libraryBase) 250} 251 252func (fuzzBin *fuzzBinary) install(ctx ModuleContext, file android.Path) { 253 fuzzBin.fuzzPackagedModule = PackageFuzzModule(ctx, fuzzBin.fuzzPackagedModule, pctx) 254 255 installBase := "fuzz" 256 257 // Grab the list of required shared libraries. 258 fuzzBin.sharedLibraries, _ = CollectAllSharedDependencies(ctx) 259 260 // TODO: does not mirror Android linkernamespaces 261 // the logic here has special cases for vendor, but it would need more work to 262 // work in arbitrary partitions, so just surface errors early for a few cases 263 // 264 // Even without these, there are certain situations across linkernamespaces 265 // that this won't support. For instance, you might have: 266 // 267 // my_fuzzer (vendor) -> libbinder_ndk (core) -> libbinder (vendor) 268 // 269 // This dependency chain wouldn't be possible to express in the current 270 // logic because all the deps currently match the variant of the source 271 // module. 272 273 for _, ruleBuilderInstall := range fuzzBin.sharedLibraries { 274 install := ruleBuilderInstall.To 275 fuzzBin.installedSharedDeps = append(fuzzBin.installedSharedDeps, 276 SharedLibraryInstallLocation( 277 install, ctx.Host(), ctx.inVendor(), installBase, ctx.Arch().ArchType.String())) 278 279 // Also add the dependency on the shared library symbols dir. 280 if !ctx.Host() { 281 fuzzBin.installedSharedDeps = append(fuzzBin.installedSharedDeps, 282 SharedLibrarySymbolsInstallLocation(install, ctx.inVendor(), installBase, ctx.Arch().ArchType.String())) 283 } 284 } 285 286 for _, d := range fuzzBin.fuzzPackagedModule.Corpus { 287 fuzzBin.data = append(fuzzBin.data, android.DataPath{SrcPath: d, RelativeInstallPath: "corpus", WithoutRel: true}) 288 } 289 290 for _, d := range fuzzBin.fuzzPackagedModule.Data { 291 fuzzBin.data = append(fuzzBin.data, android.DataPath{SrcPath: d, RelativeInstallPath: "data"}) 292 } 293 294 if d := fuzzBin.fuzzPackagedModule.Dictionary; d != nil { 295 fuzzBin.data = append(fuzzBin.data, android.DataPath{SrcPath: d, WithoutRel: true}) 296 } 297 298 if d := fuzzBin.fuzzPackagedModule.Config; d != nil { 299 fuzzBin.data = append(fuzzBin.data, android.DataPath{SrcPath: d, WithoutRel: true}) 300 } 301 302 fuzzBin.binaryDecorator.baseInstaller.dir = filepath.Join( 303 installBase, ctx.Target().Arch.ArchType.String(), ctx.ModuleName()) 304 fuzzBin.binaryDecorator.baseInstaller.dir64 = filepath.Join( 305 installBase, ctx.Target().Arch.ArchType.String(), ctx.ModuleName()) 306 fuzzBin.binaryDecorator.baseInstaller.installTestData(ctx, fuzzBin.data) 307 fuzzBin.binaryDecorator.baseInstaller.install(ctx, file) 308} 309 310func PackageFuzzModule(ctx android.ModuleContext, fuzzPackagedModule fuzz.FuzzPackagedModule, pctx android.PackageContext) fuzz.FuzzPackagedModule { 311 fuzzPackagedModule.Corpus = android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Corpus) 312 313 fuzzPackagedModule.Data = android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Data) 314 315 if fuzzPackagedModule.FuzzProperties.Dictionary != nil { 316 fuzzPackagedModule.Dictionary = android.PathForModuleSrc(ctx, *fuzzPackagedModule.FuzzProperties.Dictionary) 317 if fuzzPackagedModule.Dictionary.Ext() != ".dict" { 318 ctx.PropertyErrorf("dictionary", 319 "Fuzzer dictionary %q does not have '.dict' extension", 320 fuzzPackagedModule.Dictionary.String()) 321 } 322 } 323 324 if fuzzPackagedModule.FuzzProperties.Fuzz_config != nil { 325 configPath := android.PathForModuleOut(ctx, "config").Join(ctx, "config.json") 326 android.WriteFileRule(ctx, configPath, fuzzPackagedModule.FuzzProperties.Fuzz_config.String()) 327 fuzzPackagedModule.Config = configPath 328 } 329 return fuzzPackagedModule 330} 331 332func NewFuzzer(hod android.HostOrDeviceSupported) *Module { 333 module, binary := newBinary(hod) 334 baseInstallerPath := "fuzz" 335 336 binary.baseInstaller = NewBaseInstaller(baseInstallerPath, baseInstallerPath, InstallInData) 337 338 fuzzBin := &fuzzBinary{ 339 binaryDecorator: binary, 340 baseCompiler: NewBaseCompiler(), 341 } 342 module.compiler = fuzzBin 343 module.linker = fuzzBin 344 module.installer = fuzzBin 345 346 module.fuzzer.Properties.FuzzFramework = fuzz.LibFuzzer 347 348 // The fuzzer runtime is not present for darwin host modules, disable cc_fuzz modules when targeting darwin. 349 android.AddLoadHook(module, func(ctx android.LoadHookContext) { 350 351 extraProps := struct { 352 Sanitize struct { 353 Fuzzer *bool 354 } 355 Target struct { 356 Darwin struct { 357 Enabled *bool 358 } 359 Linux_bionic struct { 360 Enabled *bool 361 } 362 } 363 }{} 364 extraProps.Sanitize.Fuzzer = BoolPtr(true) 365 extraProps.Target.Darwin.Enabled = BoolPtr(false) 366 extraProps.Target.Linux_bionic.Enabled = BoolPtr(false) 367 ctx.AppendProperties(&extraProps) 368 369 targetFramework := fuzz.GetFramework(ctx, fuzz.Cc) 370 if !fuzz.IsValidFrameworkForModule(targetFramework, fuzz.Cc, fuzzBin.fuzzPackagedModule.FuzzProperties.Fuzzing_frameworks) { 371 ctx.Module().Disable() 372 return 373 } 374 375 if targetFramework == fuzz.AFL { 376 fuzzBin.baseCompiler.Properties.Srcs = append(fuzzBin.baseCompiler.Properties.Srcs, ":aflpp_driver", ":afl-compiler-rt") 377 module.fuzzer.Properties.FuzzFramework = fuzz.AFL 378 } 379 }) 380 381 return module 382} 383 384// Responsible for generating GNU Make rules that package fuzz targets into 385// their architecture & target/host specific zip file. 386type ccRustFuzzPackager struct { 387 fuzz.FuzzPackager 388 fuzzPackagingArchModules string 389 fuzzTargetSharedDepsInstallPairs string 390 allFuzzTargetsName string 391 onlyIncludePresubmits bool 392} 393 394func fuzzPackagingFactory() android.Singleton { 395 396 fuzzPackager := &ccRustFuzzPackager{ 397 fuzzPackagingArchModules: "SOONG_FUZZ_PACKAGING_ARCH_MODULES", 398 fuzzTargetSharedDepsInstallPairs: "FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS", 399 allFuzzTargetsName: "ALL_FUZZ_TARGETS", 400 onlyIncludePresubmits: false, 401 } 402 return fuzzPackager 403} 404 405func fuzzPackagingFactoryPresubmit() android.Singleton { 406 407 fuzzPackager := &ccRustFuzzPackager{ 408 fuzzPackagingArchModules: "SOONG_PRESUBMIT_FUZZ_PACKAGING_ARCH_MODULES", 409 fuzzTargetSharedDepsInstallPairs: "PRESUBMIT_FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS", 410 allFuzzTargetsName: "ALL_PRESUBMIT_FUZZ_TARGETS", 411 onlyIncludePresubmits: true, 412 } 413 return fuzzPackager 414} 415 416func (s *ccRustFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { 417 // Map between each architecture + host/device combination, and the files that 418 // need to be packaged (in the tuple of {source file, destination folder in 419 // archive}). 420 archDirs := make(map[fuzz.ArchOs][]fuzz.FileToZip) 421 422 // List of individual fuzz targets, so that 'make fuzz' also installs the targets 423 // to the correct output directories as well. 424 s.FuzzTargets = make(map[string]bool) 425 426 // Map tracking whether each shared library has an install rule to avoid duplicate install rules from 427 // multiple fuzzers that depend on the same shared library. 428 sharedLibraryInstalled := make(map[string]bool) 429 430 ctx.VisitAllModules(func(module android.Module) { 431 ccModule, ok := module.(LinkableInterface) 432 if !ok || ccModule.PreventInstall() { 433 return 434 } 435 // Discard non-fuzz targets. 436 if ok := fuzz.IsValid(ctx, ccModule.FuzzModuleStruct()); !ok { 437 return 438 } 439 440 sharedLibsInstallDirPrefix := "lib" 441 if ccModule.InVendor() { 442 sharedLibsInstallDirPrefix = "lib/vendor" 443 } 444 445 if !ccModule.IsFuzzModule() { 446 return 447 } 448 449 hostOrTargetString := "target" 450 if ccModule.Target().HostCross { 451 hostOrTargetString = "host_cross" 452 } else if ccModule.Host() { 453 hostOrTargetString = "host" 454 } 455 if s.onlyIncludePresubmits == true { 456 hostOrTargetString = "presubmit-" + hostOrTargetString 457 } 458 459 fpm := fuzz.FuzzPackagedModule{} 460 if ok { 461 fpm = ccModule.FuzzPackagedModule() 462 } 463 464 intermediatePath := "fuzz" 465 466 archString := ccModule.Target().Arch.ArchType.String() 467 archDir := android.PathForIntermediates(ctx, intermediatePath, hostOrTargetString, archString) 468 archOs := fuzz.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()} 469 470 var files []fuzz.FileToZip 471 builder := android.NewRuleBuilder(pctx, ctx) 472 473 // Package the corpus, data, dict and config into a zipfile. 474 files = s.PackageArtifacts(ctx, module, fpm, archDir, builder) 475 476 // Package shared libraries 477 files = append(files, GetSharedLibsToZip(ccModule.FuzzSharedLibraries(), ccModule, &s.FuzzPackager, archString, sharedLibsInstallDirPrefix, &sharedLibraryInstalled)...) 478 479 // The executable. 480 files = append(files, fuzz.FileToZip{SourceFilePath: android.OutputFileForModule(ctx, ccModule, "unstripped")}) 481 482 if s.onlyIncludePresubmits == true { 483 if fpm.FuzzProperties.Fuzz_config == nil { 484 return 485 } 486 if !BoolDefault(fpm.FuzzProperties.Fuzz_config.Use_for_presubmit, false) { 487 return 488 } 489 } 490 archDirs[archOs], ok = s.BuildZipFile(ctx, module, fpm, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs) 491 if !ok { 492 return 493 } 494 }) 495 496 s.CreateFuzzPackage(ctx, archDirs, fuzz.Cc, pctx) 497} 498 499func (s *ccRustFuzzPackager) MakeVars(ctx android.MakeVarsContext) { 500 packages := s.Packages.Strings() 501 sort.Strings(packages) 502 sort.Strings(s.FuzzPackager.SharedLibInstallStrings) 503 // TODO(mitchp): Migrate this to use MakeVarsContext::DistForGoal() when it's 504 // ready to handle phony targets created in Soong. In the meantime, this 505 // exports the phony 'fuzz' target and dependencies on packages to 506 // core/main.mk so that we can use dist-for-goals. 507 508 ctx.Strict(s.fuzzPackagingArchModules, strings.Join(packages, " ")) 509 510 ctx.Strict(s.fuzzTargetSharedDepsInstallPairs, 511 strings.Join(s.FuzzPackager.SharedLibInstallStrings, " ")) 512 513 // Preallocate the slice of fuzz targets to minimise memory allocations. 514 s.PreallocateSlice(ctx, s.allFuzzTargetsName) 515} 516 517// GetSharedLibsToZip finds and marks all the transiently-dependent shared libraries for 518// packaging. 519func GetSharedLibsToZip(sharedLibraries android.RuleBuilderInstalls, module LinkableInterface, s *fuzz.FuzzPackager, archString string, destinationPathPrefix string, sharedLibraryInstalled *map[string]bool) []fuzz.FileToZip { 520 var files []fuzz.FileToZip 521 522 fuzzDir := "fuzz" 523 524 for _, ruleBuilderInstall := range sharedLibraries { 525 library := ruleBuilderInstall.From 526 install := ruleBuilderInstall.To 527 files = append(files, fuzz.FileToZip{ 528 SourceFilePath: library, 529 DestinationPathPrefix: destinationPathPrefix, 530 DestinationPath: install, 531 }) 532 533 // For each architecture-specific shared library dependency, we need to 534 // install it to the output directory. Setup the install destination here, 535 // which will be used by $(copy-many-files) in the Make backend. 536 installDestination := SharedLibraryInstallLocation( 537 install, module.Host(), module.InVendor(), fuzzDir, archString) 538 if (*sharedLibraryInstalled)[installDestination] { 539 continue 540 } 541 (*sharedLibraryInstalled)[installDestination] = true 542 543 // Escape all the variables, as the install destination here will be called 544 // via. $(eval) in Make. 545 installDestination = strings.ReplaceAll( 546 installDestination, "$", "$$") 547 s.SharedLibInstallStrings = append(s.SharedLibInstallStrings, 548 library.String()+":"+installDestination) 549 550 // Ensure that on device, the library is also reinstalled to the /symbols/ 551 // dir. Symbolized DSO's are always installed to the device when fuzzing, but 552 // we want symbolization tools (like `stack`) to be able to find the symbols 553 // in $ANDROID_PRODUCT_OUT/symbols automagically. 554 if !module.Host() { 555 symbolsInstallDestination := SharedLibrarySymbolsInstallLocation(install, module.InVendor(), fuzzDir, archString) 556 symbolsInstallDestination = strings.ReplaceAll(symbolsInstallDestination, "$", "$$") 557 s.SharedLibInstallStrings = append(s.SharedLibInstallStrings, 558 library.String()+":"+symbolsInstallDestination) 559 } 560 } 561 return files 562} 563 564// CollectAllSharedDependencies search over the provided module's dependencies using 565// VisitDirectDeps and WalkDeps to enumerate all shared library dependencies. 566// VisitDirectDeps is used first to avoid incorrectly using the core libraries (sanitizer 567// runtimes, libc, libdl, etc.) from a dependency. This may cause issues when dependencies 568// have explicit sanitizer tags, as we may get a dependency on an unsanitized libc, etc. 569func CollectAllSharedDependencies(ctx android.ModuleContext) (android.RuleBuilderInstalls, []android.Module) { 570 seen := make(map[string]bool) 571 recursed := make(map[string]bool) 572 deps := []android.Module{} 573 574 var sharedLibraries android.RuleBuilderInstalls 575 576 // Enumerate the first level of dependencies, as we discard all non-library 577 // modules in the BFS loop below. 578 ctx.VisitDirectDeps(func(dep android.Module) { 579 if !IsValidSharedDependency(dep) { 580 return 581 } 582 sharedLibraryInfo, hasSharedLibraryInfo := android.OtherModuleProvider(ctx, dep, SharedLibraryInfoProvider) 583 if !hasSharedLibraryInfo { 584 return 585 } 586 if seen[ctx.OtherModuleName(dep)] { 587 return 588 } 589 seen[ctx.OtherModuleName(dep)] = true 590 deps = append(deps, dep) 591 592 installDestination := sharedLibraryInfo.SharedLibrary.Base() 593 ruleBuilderInstall := android.RuleBuilderInstall{android.OutputFileForModule(ctx, dep, "unstripped"), installDestination} 594 sharedLibraries = append(sharedLibraries, ruleBuilderInstall) 595 }) 596 597 ctx.WalkDeps(func(child, parent android.Module) bool { 598 599 // If this is a Rust module which is not rust_ffi_shared, we still want to bundle any transitive 600 // shared dependencies (even for rust_ffi_rlib or rust_ffi_static) 601 if rustmod, ok := child.(LinkableInterface); ok && rustmod.RustLibraryInterface() && !rustmod.Shared() { 602 if recursed[ctx.OtherModuleName(child)] { 603 return false 604 } 605 recursed[ctx.OtherModuleName(child)] = true 606 return true 607 } 608 609 if !IsValidSharedDependency(child) { 610 return false 611 } 612 sharedLibraryInfo, hasSharedLibraryInfo := android.OtherModuleProvider(ctx, child, SharedLibraryInfoProvider) 613 if !hasSharedLibraryInfo { 614 return false 615 } 616 if !seen[ctx.OtherModuleName(child)] { 617 seen[ctx.OtherModuleName(child)] = true 618 deps = append(deps, child) 619 620 installDestination := sharedLibraryInfo.SharedLibrary.Base() 621 ruleBuilderInstall := android.RuleBuilderInstall{android.OutputFileForModule(ctx, child, "unstripped"), installDestination} 622 sharedLibraries = append(sharedLibraries, ruleBuilderInstall) 623 } 624 625 if recursed[ctx.OtherModuleName(child)] { 626 return false 627 } 628 recursed[ctx.OtherModuleName(child)] = true 629 return true 630 }) 631 632 return sharedLibraries, deps 633} 634