1// Copyright 2021 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 "path/filepath" 19 "sort" 20 "strings" 21 22 "android/soong/android" 23 "android/soong/cc" 24 "android/soong/fuzz" 25 26 "github.com/google/blueprint" 27 "github.com/google/blueprint/proptools" 28) 29 30const ( 31 hostString = "host" 32 targetString = "target" 33) 34 35func init() { 36 RegisterJavaFuzzBuildComponents(android.InitRegistrationContext) 37} 38 39func RegisterJavaFuzzBuildComponents(ctx android.RegistrationContext) { 40 ctx.RegisterModuleType("java_fuzz", JavaFuzzFactory) 41 ctx.RegisterSingletonType("java_fuzz_packaging", javaFuzzPackagingFactory) 42} 43 44type JavaFuzzTest struct { 45 Test 46 fuzzPackagedModule fuzz.FuzzPackagedModule 47 jniFilePaths android.Paths 48} 49 50// java_fuzz builds and links sources into a `.jar` file for the device. 51// This generates .class files in a jar which can then be instrumented before 52// fuzzing in Android Runtime (ART: Android OS on emulator or device) 53func JavaFuzzFactory() android.Module { 54 module := &JavaFuzzTest{} 55 56 module.addHostAndDeviceProperties() 57 module.AddProperties(&module.testProperties) 58 module.AddProperties(&module.fuzzPackagedModule.FuzzProperties) 59 60 module.Module.properties.Installable = proptools.BoolPtr(true) 61 module.Module.dexpreopter.isTest = true 62 module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true) 63 64 android.AddLoadHook(module, func(ctx android.LoadHookContext) { 65 disableLinuxBionic := struct { 66 Target struct { 67 Linux_bionic struct { 68 Enabled *bool 69 } 70 } 71 }{} 72 disableLinuxBionic.Target.Linux_bionic.Enabled = proptools.BoolPtr(false) 73 ctx.AppendProperties(&disableLinuxBionic) 74 }) 75 76 InitJavaModuleMultiTargets(module, android.HostAndDeviceSupported) 77 return module 78} 79 80func (j *JavaFuzzTest) DepsMutator(ctx android.BottomUpMutatorContext) { 81 if len(j.testProperties.Jni_libs) > 0 { 82 for _, target := range ctx.MultiTargets() { 83 sharedLibVariations := append(target.Variations(), blueprint.Variation{Mutator: "link", Variation: "shared"}) 84 ctx.AddFarVariationDependencies(sharedLibVariations, jniLibTag, j.testProperties.Jni_libs...) 85 } 86 } 87 88 j.deps(ctx) 89} 90 91func (j *JavaFuzzTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { 92 if j.fuzzPackagedModule.FuzzProperties.Corpus != nil { 93 j.fuzzPackagedModule.Corpus = android.PathsForModuleSrc(ctx, j.fuzzPackagedModule.FuzzProperties.Corpus) 94 } 95 if j.fuzzPackagedModule.FuzzProperties.Data != nil { 96 j.fuzzPackagedModule.Data = android.PathsForModuleSrc(ctx, j.fuzzPackagedModule.FuzzProperties.Data) 97 } 98 if j.fuzzPackagedModule.FuzzProperties.Dictionary != nil { 99 j.fuzzPackagedModule.Dictionary = android.PathForModuleSrc(ctx, *j.fuzzPackagedModule.FuzzProperties.Dictionary) 100 } 101 if j.fuzzPackagedModule.FuzzProperties.Fuzz_config != nil { 102 configPath := android.PathForModuleOut(ctx, "config").Join(ctx, "config.json") 103 android.WriteFileRule(ctx, configPath, j.fuzzPackagedModule.FuzzProperties.Fuzz_config.String()) 104 j.fuzzPackagedModule.Config = configPath 105 } 106 107 _, sharedDeps := cc.CollectAllSharedDependencies(ctx) 108 for _, dep := range sharedDeps { 109 sharedLibInfo := ctx.OtherModuleProvider(dep, cc.SharedLibraryInfoProvider).(cc.SharedLibraryInfo) 110 if sharedLibInfo.SharedLibrary != nil { 111 arch := "lib" 112 if sharedLibInfo.Target.Arch.ArchType.Multilib == "lib64" { 113 arch = "lib64" 114 } 115 116 libPath := android.PathForModuleOut(ctx, filepath.Join(arch, sharedLibInfo.SharedLibrary.Base())) 117 ctx.Build(pctx, android.BuildParams{ 118 Rule: android.Cp, 119 Input: sharedLibInfo.SharedLibrary, 120 Output: libPath, 121 }) 122 j.jniFilePaths = append(j.jniFilePaths, libPath) 123 } else { 124 ctx.PropertyErrorf("jni_libs", "%q of type %q is not supported", dep.Name(), ctx.OtherModuleType(dep)) 125 } 126 127 } 128 129 j.Test.GenerateAndroidBuildActions(ctx) 130} 131 132type javaFuzzPackager struct { 133 fuzz.FuzzPackager 134} 135 136func javaFuzzPackagingFactory() android.Singleton { 137 return &javaFuzzPackager{} 138} 139 140func (s *javaFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { 141 // Map between each architecture + host/device combination. 142 archDirs := make(map[fuzz.ArchOs][]fuzz.FileToZip) 143 144 s.FuzzTargets = make(map[string]bool) 145 ctx.VisitAllModules(func(module android.Module) { 146 // Discard non-fuzz targets. 147 javaFuzzModule, ok := module.(*JavaFuzzTest) 148 if !ok { 149 return 150 } 151 152 hostOrTargetString := "target" 153 if javaFuzzModule.Host() { 154 hostOrTargetString = "host" 155 } 156 157 fuzzModuleValidator := fuzz.FuzzModule{ 158 javaFuzzModule.ModuleBase, 159 javaFuzzModule.DefaultableModuleBase, 160 javaFuzzModule.ApexModuleBase, 161 } 162 163 if ok := fuzz.IsValid(fuzzModuleValidator); !ok { 164 return 165 } 166 167 archString := javaFuzzModule.Arch().ArchType.String() 168 archDir := android.PathForIntermediates(ctx, "fuzz", hostOrTargetString, archString) 169 archOs := fuzz.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()} 170 171 var files []fuzz.FileToZip 172 builder := android.NewRuleBuilder(pctx, ctx) 173 174 // Package the artifacts (data, corpus, config and dictionary) into a zipfile. 175 files = s.PackageArtifacts(ctx, module, javaFuzzModule.fuzzPackagedModule, archDir, builder) 176 177 // Add .jar 178 files = append(files, fuzz.FileToZip{javaFuzzModule.implementationJarFile, ""}) 179 180 // Add jni .so files 181 for _, fPath := range javaFuzzModule.jniFilePaths { 182 files = append(files, fuzz.FileToZip{fPath, ""}) 183 } 184 185 archDirs[archOs], ok = s.BuildZipFile(ctx, module, javaFuzzModule.fuzzPackagedModule, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs) 186 if !ok { 187 return 188 } 189 }) 190 s.CreateFuzzPackage(ctx, archDirs, fuzz.Java, pctx) 191} 192 193func (s *javaFuzzPackager) MakeVars(ctx android.MakeVarsContext) { 194 packages := s.Packages.Strings() 195 sort.Strings(packages) 196 ctx.Strict("SOONG_JAVA_FUZZ_PACKAGING_ARCH_MODULES", strings.Join(packages, " ")) 197 // Preallocate the slice of fuzz targets to minimize memory allocations. 198 s.PreallocateSlice(ctx, "ALL_JAVA_FUZZ_TARGETS") 199} 200