• 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 fuzz
16
17// This file contains the common code for compiling C/C++ and Rust fuzzers for Android.
18
19import (
20	"encoding/json"
21	"fmt"
22	"sort"
23	"strings"
24
25	"github.com/google/blueprint"
26	"github.com/google/blueprint/proptools"
27
28	"android/soong/android"
29)
30
31type Lang string
32
33const (
34	Cc   Lang = "cc"
35	Rust Lang = "rust"
36	Java Lang = "java"
37)
38
39type Framework string
40
41const (
42	AFL              Framework = "afl"
43	LibFuzzer        Framework = "libfuzzer"
44	Jazzer           Framework = "jazzer"
45	UnknownFramework Framework = "unknownframework"
46)
47
48func (f Framework) Variant() string {
49	switch f {
50	case AFL:
51		return "afl"
52	case LibFuzzer:
53		return "libfuzzer"
54	case Jazzer:
55		return "jazzer"
56	default:
57		panic(fmt.Errorf("unknown fuzzer %q when getting variant", f))
58	}
59}
60
61func FrameworkFromVariant(v string) Framework {
62	switch v {
63	case "afl":
64		return AFL
65	case "libfuzzer":
66		return LibFuzzer
67	case "jazzer":
68		return Jazzer
69	default:
70		panic(fmt.Errorf("unknown variant %q when getting fuzzer", v))
71	}
72}
73
74var BoolDefault = proptools.BoolDefault
75
76type FuzzModule struct {
77	android.ModuleBase
78	android.DefaultableModuleBase
79	android.ApexModuleBase
80}
81
82type FuzzPackager struct {
83	Packages                android.Paths
84	FuzzTargets             map[string]bool
85	SharedLibInstallStrings []string
86}
87
88type FileToZip struct {
89	SourceFilePath        android.Path
90	DestinationPathPrefix string
91	DestinationPath       string
92}
93
94type ArchOs struct {
95	HostOrTarget string
96	Arch         string
97	Dir          string
98}
99
100type Vector string
101
102const (
103	unknown_access_vector Vector = "unknown_access_vector"
104	// The code being fuzzed is reachable from a remote source, or using data
105	// provided by a remote source.  For example: media codecs process media files
106	// from the internet, SMS processing handles remote message data.
107	// See
108	// https://source.android.com/docs/security/overview/updates-resources#local-vs-remote
109	// for an explanation of what's considered "remote."
110	remote = "remote"
111	// The code being fuzzed can only be reached locally, such as from an
112	// installed app.  As an example, if it's fuzzing a Binder interface, it's
113	// assumed that you'd need a local app to make arbitrary Binder calls.
114	// And the app that's calling the fuzzed code does not require any privileges;
115	// any 3rd party app could make these calls.
116	local_no_privileges_required = "local_no_privileges_required"
117	// The code being fuzzed can only be called locally, and the calling process
118	// requires additional permissions that prevent arbitrary 3rd party apps from
119	// calling the code.  For instance: this requires a privileged or signature
120	// permission to reach, or SELinux restrictions prevent the untrusted_app
121	// domain from calling it.
122	local_privileges_required = "local_privileges_required"
123	// The code is only callable on a PC host, not on a production Android device.
124	// For instance, this is fuzzing code used during the build process, or
125	// tooling that does not exist on a user's actual Android device.
126	host_access = "host_access"
127	// The code being fuzzed is only reachable if the user has enabled Developer
128	// Options, or has enabled a persistent Developer Options setting.
129	local_with_developer_options = "local_with_developer_options"
130)
131
132func (vector Vector) isValidVector() bool {
133	switch vector {
134	case "",
135		unknown_access_vector,
136		remote,
137		local_no_privileges_required,
138		local_privileges_required,
139		host_access,
140		local_with_developer_options:
141		return true
142	}
143	return false
144}
145
146type ServicePrivilege string
147
148const (
149	unknown_service_privilege ServicePrivilege = "unknown_service_privilege"
150	// The code being fuzzed runs on a Secure Element.  This has access to some
151	// of the most privileged data on the device, such as authentication keys.
152	// Not all devices have a Secure Element.
153	secure_element = "secure_element"
154	// The code being fuzzed runs in the TEE.  The TEE is designed to be resistant
155	// to a compromised kernel, and stores sensitive data.
156	trusted_execution = "trusted_execution"
157	// The code being fuzzed has privileges beyond what arbitrary 3rd party apps
158	// have.  For instance, it's running as the System UID, or it's in an SELinux
159	// domain that's able to perform calls that can't be made by 3rd party apps.
160	privileged = "privileged"
161	// The code being fuzzed is equivalent to a 3rd party app.  It runs in the
162	// untrusted_app SELinux domain, or it only has privileges that are equivalent
163	// to what a 3rd party app could have.
164	unprivileged = "unprivileged"
165	// The code being fuzzed is significantly constrained, and even if it's
166	// compromised, it has significant restrictions that prevent it from
167	// performing most actions.  This is significantly more restricted than
168	// UNPRIVILEGED.  An example is the isolatedProcess=true setting in a 3rd
169	// party app.  Or a process that's very restricted by SELinux, such as
170	// anything in the mediacodec SELinux domain.
171	constrained = "constrained"
172	// The code being fuzzed always has Negligible Security Impact.  Even
173	// arbitrary out of bounds writes and full code execution would not be
174	// considered a security vulnerability.  This typically only makes sense if
175	// FuzzedCodeUsage is set to FUTURE_VERSION or EXPERIMENTAL, and if
176	// AutomaticallyRouteTo is set to ALWAYS_NSI.
177	nsi = "nsi"
178	// The code being fuzzed only runs on a PC host, not on a production Android
179	// device.  For instance, the fuzzer is fuzzing code used during the build
180	// process, or tooling that does not exist on a user's actual Android device.
181	host_only = "host_only"
182)
183
184func (service_privilege ServicePrivilege) isValidServicePrivilege() bool {
185	switch service_privilege {
186	case "",
187		unknown_service_privilege,
188		secure_element,
189		trusted_execution,
190		privileged,
191		unprivileged,
192		constrained,
193		nsi,
194		host_only:
195		return true
196	}
197	return false
198}
199
200type UsePlatformLibs string
201
202const (
203	unknown_use_platform_libs UsePlatformLibs = "unknown_use_platform_libs"
204	// Use the native libraries on the device, typically in /system directory
205	use_platform_libs = "use_platform_libs"
206	// Do not use any native libraries (ART will not be initialized)
207	use_none = "use_none"
208)
209
210func (use_platform_libs UsePlatformLibs) isValidUsePlatformLibs() bool {
211	switch use_platform_libs {
212	case "",
213		unknown_use_platform_libs,
214		use_platform_libs,
215		use_none:
216		return true
217	}
218	return false
219}
220
221type UserData string
222
223const (
224	unknown_user_data UserData = "unknown_user_data"
225	// The process being fuzzed only handles data from a single user, or from a
226	// single process or app.  It's possible the process shuts down before
227	// handling data from another user/process/app, or it's possible the process
228	// only ever handles one user's/process's/app's data.  As an example, some
229	// print spooler processes are started for a single document and terminate
230	// when done, so each instance only handles data from a single user/app.
231	single_user = "single_user"
232	// The process handles data from multiple users, or from multiple other apps
233	// or processes.  Media processes, for instance, can handle media requests
234	// from multiple different apps without restarting.  Wi-Fi and network
235	// processes handle data from multiple users, and processes, and apps.
236	multi_user = "multi_user"
237)
238
239func (user_data UserData) isValidUserData() bool {
240	switch user_data {
241	case "",
242		unknown_user_data,
243		single_user,
244		multi_user:
245		return true
246	}
247	return false
248}
249
250type FuzzedCodeUsage string
251
252const (
253	undefined FuzzedCodeUsage = "undefined"
254	unknown                   = "unknown"
255	// The code being fuzzed exists in a shipped version of Android and runs on
256	// devices in production.
257	shipped = "shipped"
258	// The code being fuzzed is not yet in a shipping version of Android, but it
259	// will be at some point in the future.
260	future_version = "future_version"
261	// The code being fuzzed is not in a shipping version of Android, and there
262	// are no plans to ship it in the future.
263	experimental = "experimental"
264)
265
266func (fuzzed_code_usage FuzzedCodeUsage) isValidFuzzedCodeUsage() bool {
267	switch fuzzed_code_usage {
268	case "",
269		undefined,
270		unknown,
271		shipped,
272		future_version,
273		experimental:
274		return true
275	}
276	return false
277}
278
279type AutomaticallyRouteTo string
280
281const (
282	undefined_routing AutomaticallyRouteTo = "undefined_routing"
283	// Automatically route this to the Android Automotive security team for
284	// assessment.
285	android_automotive = "android_automotive"
286	// This should not be used in fuzzer configurations.  It is used internally
287	// by Severity Assigner to flag memory leak reports.
288	memory_leak = "memory_leak"
289	// Route this vulnerability to our Ittiam vendor team for assessment.
290	ittiam = "ittiam"
291	// Reports from this fuzzer are always NSI (see the NSI ServicePrivilegeEnum
292	// value for additional context).  It is not possible for this code to ever
293	// have a security vulnerability.
294	always_nsi = "always_nsi"
295	// Route this vulnerability to AIDL team for assessment.
296	aidl = "aidl"
297)
298
299func (automatically_route_to AutomaticallyRouteTo) isValidAutomaticallyRouteTo() bool {
300	switch automatically_route_to {
301	case "",
302		undefined_routing,
303		android_automotive,
304		memory_leak,
305		ittiam,
306		always_nsi,
307		aidl:
308		return true
309	}
310	return false
311}
312
313func IsValidConfig(fuzzModule *FuzzPackagedModuleInfo, moduleName string) bool {
314	var config = fuzzModule.FuzzConfig
315	if config != nil {
316		if !config.Vector.isValidVector() {
317			panic(fmt.Errorf("Invalid vector in fuzz config in %s", moduleName))
318		}
319
320		if !config.ServicePrivilege.isValidServicePrivilege() {
321			panic(fmt.Errorf("Invalid service_privilege in fuzz config in %s", moduleName))
322		}
323
324		if !config.Users.isValidUserData() {
325			panic(fmt.Errorf("Invalid users (user_data) in fuzz config in %s", moduleName))
326		}
327
328		if !config.FuzzedCodeUsage.isValidFuzzedCodeUsage() {
329			panic(fmt.Errorf("Invalid fuzzed_code_usage in fuzz config in %s", moduleName))
330		}
331
332		if !config.AutomaticallyRouteTo.isValidAutomaticallyRouteTo() {
333			panic(fmt.Errorf("Invalid automatically_route_to in fuzz config in %s", moduleName))
334		}
335
336		if !config.UsePlatformLibs.isValidUsePlatformLibs() {
337			panic(fmt.Errorf("Invalid use_platform_libs in fuzz config in %s", moduleName))
338		}
339	}
340	return true
341}
342
343type FuzzConfig struct {
344	// Email address of people to CC on bugs or contact about this fuzz target.
345	Cc []string `json:"cc,omitempty"`
346	// A brief description of what the fuzzed code does.
347	Description string `json:"description,omitempty"`
348	// Whether the code being fuzzed is remotely accessible or requires privileges
349	// to access locally.
350	Vector Vector `json:"vector,omitempty"`
351	// How privileged the service being fuzzed is.
352	Service_privilege ServicePrivilege `json:"service_privilege,omitempty"`
353	// Whether the service being fuzzed handles data from multiple users or only
354	// a single one.
355	Users UserData `json:"users,omitempty"`
356	// Specifies the use state of the code being fuzzed. This state factors into
357	// how an issue is handled.
358	Fuzzed_code_usage FuzzedCodeUsage `json:"fuzzed_code_usage,omitempty"`
359	// Comment describing how we came to these settings for this fuzzer.
360	Config_comment string
361	// Which team to route this to, if it should be routed automatically.
362	Automatically_route_to AutomaticallyRouteTo `json:"automatically_route_to,omitempty"`
363	// Can third party/untrusted apps supply data to fuzzed code.
364	Untrusted_data *bool `json:"untrusted_data,omitempty"`
365	// When code was released or will be released.
366	Production_date string `json:"production_date,omitempty"`
367	// Prevents critical service functionality like phone calls, bluetooth, etc.
368	Critical *bool `json:"critical,omitempty"`
369	// Specify whether to enable continuous fuzzing on devices. Defaults to true.
370	Fuzz_on_haiku_device *bool `json:"fuzz_on_haiku_device,omitempty"`
371	// Specify whether to enable continuous fuzzing on host. Defaults to true.
372	Fuzz_on_haiku_host *bool `json:"fuzz_on_haiku_host,omitempty"`
373	// Component in Google's bug tracking system that bugs should be filed to.
374	Componentid *int64 `json:"componentid,omitempty"`
375	// Hotlist(s) in Google's bug tracking system that bugs should be marked with.
376	Hotlists []string `json:"hotlists,omitempty"`
377	// Specify whether this fuzz target was submitted by a researcher. Defaults
378	// to false.
379	Researcher_submitted *bool `json:"researcher_submitted,omitempty"`
380	// Specify who should be acknowledged for CVEs in the Android Security
381	// Bulletin.
382	Acknowledgement []string `json:"acknowledgement,omitempty"`
383	// Additional options to be passed to libfuzzer when run in Haiku.
384	Libfuzzer_options []string `json:"libfuzzer_options,omitempty"`
385	// Additional options to be passed to HWASAN when running on-device in Haiku.
386	Hwasan_options []string `json:"hwasan_options,omitempty"`
387	// Additional options to be passed to HWASAN when running on host in Haiku.
388	Asan_options []string `json:"asan_options,omitempty"`
389	// If there's a Java fuzzer with JNI, a different version of Jazzer would
390	// need to be added to the fuzzer package than one without JNI
391	IsJni *bool `json:"is_jni,omitempty"`
392	// List of modules for monitoring coverage drops in directories (e.g. "libicu")
393	Target_modules []string `json:"target_modules,omitempty"`
394	// Specifies a bug assignee to replace default ISE assignment
395	Triage_assignee string `json:"triage_assignee,omitempty"`
396	// Specifies libs used to initialize ART (java only, 'use_none' for no initialization)
397	Use_platform_libs UsePlatformLibs `json:"use_platform_libs,omitempty"`
398	// Specifies whether fuzz target should check presubmitted code changes for crashes.
399	// Defaults to false.
400	Use_for_presubmit *bool `json:"use_for_presubmit,omitempty"`
401	// Specify which paths to exclude from fuzzing coverage reports
402	Exclude_paths_from_reports []string `json:"exclude_paths_from_reports,omitempty"`
403}
404
405type FuzzFrameworks struct {
406	Afl       *bool
407	Libfuzzer *bool
408	Jazzer    *bool
409}
410
411type FuzzProperties struct {
412	// Optional list of seed files to be installed to the fuzz target's output
413	// directory.
414	Corpus []string `android:"path"`
415
416	// Same as corpus, but adds dependencies on module references using the device's os variant
417	// and the common arch variant.
418	Device_common_corpus []string `android:"path_device_common"`
419
420	// Optional list of data files to be installed to the fuzz target's output
421	// directory. Directory structure relative to the module is preserved.
422	Data []string `android:"path"`
423	// Same as data, but adds dependencies on modules using the device's os variant, and common
424	// architecture's variant. Can be useful to add device-built apps to the data of a host
425	// test.
426	Device_common_data []string `android:"path_device_common"`
427	// Same as data, but adds dependencies on modules using the device's os variant, and the
428	// device's first architecture's variant. Can be useful to add device-built apps to the data
429	// of a host test.
430	Device_first_data []string `android:"path_device_first"`
431
432	// Same as data, but will add dependencies on modules using the host's os variation and
433	// the common arch variation. Useful for a device test that wants to depend on a host
434	// module, for example to include a custom Tradefed test runner.
435	Host_common_data []string `android:"path_host_common"`
436
437	// Optional dictionary to be installed to the fuzz target's output directory.
438	Dictionary *string `android:"path"`
439	// Define the fuzzing frameworks this fuzz target can be built for. If
440	// empty then the fuzz target will be available to be  built for all fuzz
441	// frameworks available
442	Fuzzing_frameworks *FuzzFrameworks
443	// Config for running the target on fuzzing infrastructure.
444	Fuzz_config *FuzzConfig
445}
446
447type FuzzPackagedModule struct {
448	FuzzProperties FuzzProperties
449	Dictionary     android.Path
450	Corpus         android.Paths
451	Config         android.Path
452	Data           android.Paths
453}
454
455type FuzzConfigInfo struct {
456	Vector Vector
457	// How privileged the service being fuzzed is.
458	ServicePrivilege ServicePrivilege
459	// Whether the service being fuzzed handles data from multiple users or only
460	// a single one.
461	Users UserData
462	// Specifies the use state of the code being fuzzed. This state factors into
463	// how an issue is handled.
464	FuzzedCodeUsage FuzzedCodeUsage
465	// Which team to route this to, if it should be routed automatically.
466	AutomaticallyRouteTo AutomaticallyRouteTo
467	// Specifies libs used to initialize ART (java only, 'use_none' for no initialization)
468	UsePlatformLibs UsePlatformLibs
469	// Specify whether to enable continuous fuzzing on devices. Defaults to true.
470	FuzzOnHaikuDevice bool
471	// Specify whether to enable continuous fuzzing on host. Defaults to true.
472	FuzzOnHaikuHost bool
473	// Specifies whether fuzz target should check presubmitted code changes for crashes.
474	// Defaults to false.
475	UseForPresubmit bool
476}
477type FuzzPackagedModuleInfo struct {
478	FuzzConfig *FuzzConfigInfo
479	Dictionary android.Path
480	Corpus     android.Paths
481	Config     android.Path
482	Data       android.Paths
483}
484
485var FuzzPackagedModuleInfoProvider = blueprint.NewProvider[FuzzPackagedModuleInfo]()
486
487func SetFuzzPackagedModuleInfo(ctx android.ModuleContext, fm *FuzzPackagedModule) {
488	info := FuzzPackagedModuleInfo{
489		Dictionary: fm.Dictionary,
490		Config:     fm.Config,
491		Corpus:     fm.Corpus,
492		Data:       fm.Data,
493	}
494	if fm.FuzzProperties.Fuzz_config != nil {
495		info.FuzzConfig = &FuzzConfigInfo{
496			Vector:               fm.FuzzProperties.Fuzz_config.Vector,
497			ServicePrivilege:     fm.FuzzProperties.Fuzz_config.Service_privilege,
498			Users:                fm.FuzzProperties.Fuzz_config.Users,
499			FuzzedCodeUsage:      fm.FuzzProperties.Fuzz_config.Fuzzed_code_usage,
500			AutomaticallyRouteTo: fm.FuzzProperties.Fuzz_config.Automatically_route_to,
501			FuzzOnHaikuDevice:    BoolDefault(fm.FuzzProperties.Fuzz_config.Fuzz_on_haiku_device, true),
502			FuzzOnHaikuHost:      BoolDefault(fm.FuzzProperties.Fuzz_config.Fuzz_on_haiku_host, true),
503			UsePlatformLibs:      fm.FuzzProperties.Fuzz_config.Use_platform_libs,
504			UseForPresubmit:      BoolDefault(fm.FuzzProperties.Fuzz_config.Use_for_presubmit, false),
505		}
506	}
507
508	android.SetProvider(ctx, FuzzPackagedModuleInfoProvider, info)
509}
510
511func GetFramework(ctx android.LoadHookContext, lang Lang) Framework {
512	framework := ctx.Config().Getenv("FUZZ_FRAMEWORK")
513
514	if lang == Cc {
515		switch strings.ToLower(framework) {
516		case "":
517			return LibFuzzer
518		case "libfuzzer":
519			return LibFuzzer
520		case "afl":
521			return AFL
522		}
523	} else if lang == Rust {
524		return LibFuzzer
525	} else if lang == Java {
526		return Jazzer
527	}
528
529	ctx.ModuleErrorf(fmt.Sprintf("%s is not a valid fuzzing framework for %s", framework, lang))
530	return UnknownFramework
531}
532
533func IsValidFrameworkForModule(targetFramework Framework, lang Lang, moduleFrameworks *FuzzFrameworks) bool {
534	if targetFramework == UnknownFramework {
535		return false
536	}
537
538	if moduleFrameworks == nil {
539		return true
540	}
541
542	switch targetFramework {
543	case LibFuzzer:
544		return proptools.BoolDefault(moduleFrameworks.Libfuzzer, true)
545	case AFL:
546		return proptools.BoolDefault(moduleFrameworks.Afl, true)
547	case Jazzer:
548		return proptools.BoolDefault(moduleFrameworks.Jazzer, true)
549	default:
550		panic("%s is not supported as a fuzz framework")
551	}
552}
553
554func IsValid(ctx android.ConfigurableEvaluatorContext, fuzzModule FuzzModule) bool {
555	// Discard ramdisk + vendor_ramdisk + recovery modules, they're duplicates of
556	// fuzz targets we're going to package anyway.
557	if !fuzzModule.Enabled(ctx) || fuzzModule.InRamdisk() || fuzzModule.InVendorRamdisk() || fuzzModule.InRecovery() {
558		return false
559	}
560
561	// Discard modules that are in an unavailable namespace.
562	if !fuzzModule.ExportedToMake() {
563		return false
564	}
565
566	return true
567}
568
569// TODO(b/397766191): Change the signature to take ModuleProxy
570// Please only access the module's internal data through providers.
571func (s *FuzzPackager) PackageArtifacts(ctx android.SingletonContext, module android.Module, fuzzModule *FuzzPackagedModuleInfo, archDir android.OutputPath, builder *android.RuleBuilder) []FileToZip {
572	// Package the corpora into a zipfile.
573	var files []FileToZip
574	if fuzzModule.Corpus != nil {
575		corpusZip := archDir.Join(ctx, module.Name()+"_seed_corpus.zip")
576		command := builder.Command().BuiltTool("soong_zip").
577			Flag("-j").
578			FlagWithOutput("-o ", corpusZip)
579		rspFile := corpusZip.ReplaceExtension(ctx, "rsp")
580		command.FlagWithRspFileInputList("-r ", rspFile, fuzzModule.Corpus)
581		files = append(files, FileToZip{SourceFilePath: corpusZip})
582	}
583
584	// Package the data into a zipfile.
585	if fuzzModule.Data != nil {
586		dataZip := archDir.Join(ctx, module.Name()+"_data.zip")
587		command := builder.Command().BuiltTool("soong_zip").
588			FlagWithOutput("-o ", dataZip)
589		for _, f := range fuzzModule.Data {
590			intermediateDir := strings.TrimSuffix(f.String(), f.Rel())
591			command.FlagWithArg("-C ", intermediateDir)
592			command.FlagWithInput("-f ", f)
593		}
594		files = append(files, FileToZip{SourceFilePath: dataZip})
595	}
596
597	// The dictionary.
598	if fuzzModule.Dictionary != nil {
599		files = append(files, FileToZip{SourceFilePath: fuzzModule.Dictionary})
600	}
601
602	// Additional fuzz config.
603	if fuzzModule.Config != nil && IsValidConfig(fuzzModule, module.Name()) {
604		files = append(files, FileToZip{SourceFilePath: fuzzModule.Config})
605	}
606
607	return files
608}
609
610// TODO(b/397766191): Change the signature to take ModuleProxy
611// Please only access the module's internal data through providers.
612func (s *FuzzPackager) BuildZipFile(ctx android.SingletonContext, module android.Module, fuzzModule *FuzzPackagedModuleInfo, files []FileToZip, builder *android.RuleBuilder, archDir android.OutputPath, archString string, hostOrTargetString string, archOs ArchOs, archDirs map[ArchOs][]FileToZip) ([]FileToZip, bool) {
613	fuzzZip := archDir.Join(ctx, module.Name()+".zip")
614
615	command := builder.Command().BuiltTool("soong_zip").
616		Flag("-j").
617		FlagWithOutput("-o ", fuzzZip)
618
619	for _, file := range files {
620		if file.DestinationPathPrefix != "" {
621			command.FlagWithArg("-P ", file.DestinationPathPrefix)
622		} else {
623			command.Flag("-P ''")
624		}
625		if file.DestinationPath != "" {
626			command.FlagWithArg("-e ", file.DestinationPath)
627		}
628		command.FlagWithInput("-f ", file.SourceFilePath)
629	}
630
631	builder.Build("create-"+fuzzZip.String(),
632		"Package "+module.Name()+" for "+archString+"-"+hostOrTargetString)
633
634	if config := fuzzModule.FuzzConfig; config != nil {
635		if strings.Contains(hostOrTargetString, "host") && !config.FuzzOnHaikuHost {
636			return archDirs[archOs], false
637		} else if !strings.Contains(hostOrTargetString, "host") && !config.FuzzOnHaikuDevice {
638			return archDirs[archOs], false
639		}
640	}
641
642	s.FuzzTargets[module.Name()] = true
643	archDirs[archOs] = append(archDirs[archOs], FileToZip{SourceFilePath: fuzzZip})
644
645	return archDirs[archOs], true
646}
647
648func (f *FuzzConfig) String() string {
649	b, err := json.Marshal(f)
650	if err != nil {
651		panic(err)
652	}
653
654	return string(b)
655}
656
657func (s *FuzzPackager) CreateFuzzPackage(ctx android.SingletonContext, archDirs map[ArchOs][]FileToZip, fuzzType Lang, pctx android.PackageContext) {
658	var archOsList []ArchOs
659	for archOs := range archDirs {
660		archOsList = append(archOsList, archOs)
661	}
662	sort.Slice(archOsList, func(i, j int) bool { return archOsList[i].Dir < archOsList[j].Dir })
663
664	for _, archOs := range archOsList {
665		filesToZip := archDirs[archOs]
666		arch := archOs.Arch
667		hostOrTarget := archOs.HostOrTarget
668		builder := android.NewRuleBuilder(pctx, ctx)
669		zipFileName := "fuzz-" + hostOrTarget + "-" + arch + ".zip"
670		if fuzzType == Rust {
671			zipFileName = "fuzz-rust-" + hostOrTarget + "-" + arch + ".zip"
672		}
673		if fuzzType == Java {
674			zipFileName = "fuzz-java-" + hostOrTarget + "-" + arch + ".zip"
675		}
676
677		outputFile := android.PathForOutput(ctx, zipFileName)
678
679		s.Packages = append(s.Packages, outputFile)
680
681		command := builder.Command().BuiltTool("soong_zip").
682			Flag("-j").
683			FlagWithOutput("-o ", outputFile).
684			Flag("-L 0") // No need to try and re-compress the zipfiles.
685
686		for _, fileToZip := range filesToZip {
687			if fileToZip.DestinationPathPrefix != "" {
688				command.FlagWithArg("-P ", fileToZip.DestinationPathPrefix)
689			} else {
690				command.Flag("-P ''")
691			}
692			command.FlagWithInput("-f ", fileToZip.SourceFilePath)
693
694		}
695		builder.Build("create-fuzz-package-"+arch+"-"+hostOrTarget,
696			"Create fuzz target packages for "+arch+"-"+hostOrTarget)
697	}
698}
699
700func (s *FuzzPackager) PreallocateSlice(ctx android.MakeVarsContext, targets string) {
701	fuzzTargets := make([]string, 0, len(s.FuzzTargets))
702	for target, _ := range s.FuzzTargets {
703		fuzzTargets = append(fuzzTargets, target)
704	}
705
706	sort.Strings(fuzzTargets)
707	ctx.Strict(targets, strings.Join(fuzzTargets, " "))
708}
709