• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2018 The Android Open Source Project
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 bpf
16
17import (
18	"fmt"
19	"io"
20	"path/filepath"
21	"runtime"
22	"strings"
23
24	"android/soong/android"
25	"android/soong/cc"
26
27	"github.com/google/blueprint"
28	"github.com/google/blueprint/proptools"
29)
30
31func init() {
32	registerBpfBuildComponents(android.InitRegistrationContext)
33	pctx.Import("android/soong/cc/config")
34	pctx.StaticVariable("relPwd", cc.PwdPrefix())
35}
36
37var (
38	pctx = android.NewPackageContext("android/soong/bpf")
39
40	ccRule = pctx.AndroidRemoteStaticRule("ccRule", android.RemoteRuleSupports{Goma: true},
41		blueprint.RuleParams{
42			Depfile:     "${out}.d",
43			Deps:        blueprint.DepsGCC,
44			Command:     "$relPwd $ccCmd --target=bpf -c $cFlags -MD -MF ${out}.d -o $out $in",
45			CommandDeps: []string{"$ccCmd"},
46		},
47		"ccCmd", "cFlags")
48
49	stripRule = pctx.AndroidStaticRule("stripRule",
50		blueprint.RuleParams{
51			Command: `$stripCmd --strip-unneeded --remove-section=.rel.BTF ` +
52				`--remove-section=.rel.BTF.ext --remove-section=.BTF.ext $in -o $out`,
53			CommandDeps: []string{"$stripCmd"},
54		},
55		"stripCmd")
56)
57
58func registerBpfBuildComponents(ctx android.RegistrationContext) {
59	ctx.RegisterModuleType("bpf_defaults", defaultsFactory)
60	ctx.RegisterModuleType("bpf", BpfFactory)
61}
62
63type BpfInfo struct {
64	SubDir string
65}
66
67var BpfInfoProvider = blueprint.NewProvider[BpfInfo]()
68
69var PrepareForTestWithBpf = android.FixtureRegisterWithContext(registerBpfBuildComponents)
70
71// BpfModule interface is used by the apex package to gather information from a bpf module.
72type BpfModule interface {
73	android.Module
74
75	// Returns the sub install directory if the bpf module is included by apex.
76	SubDir() string
77}
78
79type BpfProperties struct {
80	// source paths to the files.
81	Srcs []string `android:"path"`
82
83	// additional cflags that should be used to build the bpf variant of
84	// the C/C++ module.
85	Cflags []string
86
87	// list of directories relative to the root of the source tree that
88	// will be added to the include paths using -I.
89	// If possible, don't use this. If adding paths from the current
90	// directory, use local_include_dirs. If adding paths from other
91	// modules, use export_include_dirs in that module.
92	Include_dirs []string
93
94	// list of directories relative to the Blueprint file that will be
95	// added to the include path using -I.
96	Local_include_dirs []string
97	// optional subdirectory under which this module is installed into.
98	Sub_dir string
99
100	// if set to true, generate BTF debug info for maps & programs.
101	Btf *bool
102
103	Vendor *bool
104
105	VendorInternal bool `blueprint:"mutated"`
106}
107
108type bpf struct {
109	android.ModuleBase
110	android.DefaultableModuleBase
111	properties BpfProperties
112
113	objs android.Paths
114}
115
116var _ android.ImageInterface = (*bpf)(nil)
117
118func (bpf *bpf) ImageMutatorBegin(ctx android.ImageInterfaceContext) {}
119
120func (bpf *bpf) VendorVariantNeeded(ctx android.ImageInterfaceContext) bool {
121	return proptools.Bool(bpf.properties.Vendor)
122}
123
124func (bpf *bpf) ProductVariantNeeded(ctx android.ImageInterfaceContext) bool {
125	return false
126}
127
128func (bpf *bpf) CoreVariantNeeded(ctx android.ImageInterfaceContext) bool {
129	return !proptools.Bool(bpf.properties.Vendor)
130}
131
132func (bpf *bpf) RamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
133	return false
134}
135
136func (bpf *bpf) VendorRamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
137	return false
138}
139
140func (bpf *bpf) DebugRamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool {
141	return false
142}
143
144func (bpf *bpf) RecoveryVariantNeeded(ctx android.ImageInterfaceContext) bool {
145	return false
146}
147
148func (bpf *bpf) ExtraImageVariations(ctx android.ImageInterfaceContext) []string {
149	return nil
150}
151
152func (bpf *bpf) SetImageVariation(ctx android.ImageInterfaceContext, variation string) {
153	bpf.properties.VendorInternal = variation == "vendor"
154}
155
156func (bpf *bpf) GenerateAndroidBuildActions(ctx android.ModuleContext) {
157	cflags := []string{
158		"-nostdlibinc",
159
160		// Make paths in deps files relative
161		"-no-canonical-prefixes",
162
163		"-O2",
164		"-Wall",
165		"-Werror",
166		"-Wextra",
167
168		"-isystem bionic/libc/include",
169		"-isystem bionic/libc/kernel/uapi",
170		// The architecture doesn't matter here, but asm/types.h is included by linux/types.h.
171		"-isystem bionic/libc/kernel/uapi/asm-arm64",
172		"-isystem bionic/libc/kernel/android/uapi",
173		"-I       packages/modules/Connectivity/bpf/headers/include",
174		// TODO(b/149785767): only give access to specific file with AID_* constants
175		"-I       system/core/libcutils/include",
176		"-I " + ctx.ModuleDir(),
177	}
178
179	for _, dir := range android.PathsForModuleSrc(ctx, bpf.properties.Local_include_dirs) {
180		cflags = append(cflags, "-I "+dir.String())
181	}
182
183	for _, dir := range android.PathsForSource(ctx, bpf.properties.Include_dirs) {
184		cflags = append(cflags, "-I "+dir.String())
185	}
186
187	cflags = append(cflags, bpf.properties.Cflags...)
188
189	if proptools.BoolDefault(bpf.properties.Btf, true) {
190		cflags = append(cflags, "-g")
191		if runtime.GOOS != "darwin" {
192			cflags = append(cflags, "-fdebug-prefix-map=/proc/self/cwd=")
193		}
194	}
195
196	srcs := android.PathsForModuleSrc(ctx, bpf.properties.Srcs)
197
198	for _, src := range srcs {
199		if strings.ContainsRune(filepath.Base(src.String()), '_') {
200			ctx.ModuleErrorf("invalid character '_' in source name")
201		}
202		obj := android.ObjPathWithExt(ctx, "unstripped", src, "o")
203
204		ctx.Build(pctx, android.BuildParams{
205			Rule:   ccRule,
206			Input:  src,
207			Output: obj,
208			Args: map[string]string{
209				"cFlags": strings.Join(cflags, " "),
210				"ccCmd":  "${config.ClangBin}/clang",
211			},
212		})
213
214		if proptools.BoolDefault(bpf.properties.Btf, true) {
215			objStripped := android.ObjPathWithExt(ctx, "", src, "o")
216			ctx.Build(pctx, android.BuildParams{
217				Rule:   stripRule,
218				Input:  obj,
219				Output: objStripped,
220				Args: map[string]string{
221					"stripCmd": "${config.ClangBin}/llvm-strip",
222				},
223			})
224			bpf.objs = append(bpf.objs, objStripped.WithoutRel())
225		} else {
226			bpf.objs = append(bpf.objs, obj.WithoutRel())
227		}
228
229	}
230
231	installDir := android.PathForModuleInstall(ctx, "etc", "bpf")
232	if len(bpf.properties.Sub_dir) > 0 {
233		installDir = installDir.Join(ctx, bpf.properties.Sub_dir)
234	}
235	for _, obj := range bpf.objs {
236		ctx.PackageFile(installDir, obj.Base(), obj)
237	}
238
239	android.SetProvider(ctx, BpfInfoProvider, BpfInfo{
240		SubDir: bpf.SubDir(),
241	})
242
243	ctx.SetOutputFiles(bpf.objs, "")
244}
245
246func (bpf *bpf) AndroidMk() android.AndroidMkData {
247	return android.AndroidMkData{
248		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
249			var names []string
250			fmt.Fprintln(w)
251			fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
252			fmt.Fprintln(w)
253			var localModulePath string
254			if bpf.properties.VendorInternal {
255				localModulePath = "LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_ETC)/bpf"
256			} else {
257				localModulePath = "LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/bpf"
258			}
259			if len(bpf.properties.Sub_dir) > 0 {
260				localModulePath += "/" + bpf.properties.Sub_dir
261			}
262			for _, obj := range bpf.objs {
263				objName := name + "_" + obj.Base()
264				names = append(names, objName)
265				fmt.Fprintln(w, "include $(CLEAR_VARS)", " # bpf.bpf.obj")
266				fmt.Fprintln(w, "LOCAL_MODULE := ", objName)
267				fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", obj.String())
268				fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", obj.Base())
269				fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC")
270				fmt.Fprintln(w, localModulePath)
271				// AconfigUpdateAndroidMkData may have added elements to Extra.  Process them here.
272				for _, extra := range data.Extra {
273					extra(w, nil)
274				}
275				fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
276				fmt.Fprintln(w)
277			}
278			fmt.Fprintln(w, "include $(CLEAR_VARS)", " # bpf.bpf")
279			fmt.Fprintln(w, "LOCAL_MODULE := ", name)
280			android.AndroidMkEmitAssignList(w, "LOCAL_REQUIRED_MODULES", names)
281			fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
282		},
283	}
284}
285
286type Defaults struct {
287	android.ModuleBase
288	android.DefaultsModuleBase
289}
290
291func defaultsFactory() android.Module {
292	return DefaultsFactory()
293}
294
295func DefaultsFactory(props ...interface{}) android.Module {
296	module := &Defaults{}
297
298	module.AddProperties(props...)
299	module.AddProperties(&BpfProperties{})
300
301	android.InitDefaultsModule(module)
302
303	return module
304}
305
306func (bpf *bpf) SubDir() string {
307	return bpf.properties.Sub_dir
308}
309
310func BpfFactory() android.Module {
311	module := &bpf{}
312
313	module.AddProperties(&module.properties)
314
315	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
316	android.InitDefaultableModule(module)
317
318	return module
319}
320