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