• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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