fuzz.go 19 KB

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