1// Copyright 2017 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 cc 16 17import ( 18 "sync" 19 20 "android/soong/android" 21 "android/soong/cc/config" 22) 23 24var ( 25 lsdumpPathsLock sync.Mutex 26 lsdumpKey = android.NewOnceKey("lsdump") 27) 28 29func lsdumpPaths(config android.Config) *[]string { 30 return config.Once(lsdumpKey, func() any { 31 return &[]string{} 32 }).(*[]string) 33} 34 35type lsdumpTag string 36 37const ( 38 apexLsdumpTag lsdumpTag = "APEX" 39 llndkLsdumpTag lsdumpTag = "LLNDK" 40 platformLsdumpTag lsdumpTag = "PLATFORM" 41 productLsdumpTag lsdumpTag = "PRODUCT" 42 vendorLsdumpTag lsdumpTag = "VENDOR" 43) 44 45// Return the prebuilt ABI dump directory for a tag; an empty string for an opt-in dump. 46func (tag *lsdumpTag) dirName() string { 47 switch *tag { 48 case apexLsdumpTag: 49 return "platform" 50 case llndkLsdumpTag: 51 return "vndk" 52 default: 53 return "" 54 } 55} 56 57// Properties for ABI compatibility checker in Android.bp. 58type headerAbiCheckerProperties struct { 59 // Enable ABI checks (even if this is not an LLNDK/VNDK lib) 60 Enabled *bool 61 62 // Path to a symbol file that specifies the symbols to be included in the generated 63 // ABI dump file 64 Symbol_file *string `android:"path"` 65 66 // Symbol versions that should be ignored from the symbol file 67 Exclude_symbol_versions []string 68 69 // Symbol tags that should be ignored from the symbol file 70 Exclude_symbol_tags []string 71 72 // Run checks on all APIs (in addition to the ones referred by 73 // one of exported ELF symbols.) 74 Check_all_apis *bool 75 76 // Extra flags passed to header-abi-diff 77 Diff_flags []string 78 79 // Opt-in reference dump directories 80 Ref_dump_dirs []string 81} 82 83func (props *headerAbiCheckerProperties) enabled() bool { 84 return Bool(props.Enabled) 85} 86 87func (props *headerAbiCheckerProperties) explicitlyDisabled() bool { 88 return !BoolDefault(props.Enabled, true) 89} 90 91type SAbiProperties struct { 92 // Whether ABI dump should be created for this module. 93 // Set by `sabiTransitionMutator` if this module is a shared library that needs ABI check, 94 // or a static library that is depended on by an ABI checked library. 95 ShouldCreateSourceAbiDump bool `blueprint:"mutated"` 96 97 // Include directories that may contain ABI information exported by a library. 98 // These directories are passed to the header-abi-dumper. 99 ReexportedIncludes []string `blueprint:"mutated"` 100 ReexportedSystemIncludes []string `blueprint:"mutated"` 101} 102 103type sabi struct { 104 Properties SAbiProperties 105} 106 107func (sabi *sabi) props() []interface{} { 108 return []interface{}{&sabi.Properties} 109} 110 111func (sabi *sabi) flags(ctx ModuleContext, flags Flags) Flags { 112 // Filter out flags which libTooling don't understand. 113 // This is here for legacy reasons and future-proof, in case the version of libTooling and clang 114 // diverge. 115 flags.Local.ToolingCFlags = config.ClangLibToolingFilterUnknownCflags(flags.Local.CFlags) 116 flags.Global.ToolingCFlags = config.ClangLibToolingFilterUnknownCflags(flags.Global.CFlags) 117 flags.Local.ToolingCppFlags = config.ClangLibToolingFilterUnknownCflags(flags.Local.CppFlags) 118 flags.Global.ToolingCppFlags = config.ClangLibToolingFilterUnknownCflags(flags.Global.CppFlags) 119 return flags 120} 121 122// Returns true if ABI dump should be created for this library, either because library is ABI 123// checked or is depended on by an ABI checked library. 124// Could be called as a nil receiver. 125func (sabi *sabi) shouldCreateSourceAbiDump() bool { 126 return sabi != nil && sabi.Properties.ShouldCreateSourceAbiDump 127} 128 129// Returns a slice of strings that represent the ABI dumps generated for this module. 130func classifySourceAbiDump(m *Module) []lsdumpTag { 131 result := []lsdumpTag{} 132 headerAbiChecker := m.library.getHeaderAbiCheckerProperties(m) 133 if headerAbiChecker.explicitlyDisabled() { 134 return result 135 } 136 if !m.InProduct() && !m.InVendor() { 137 if m.isImplementationForLLNDKPublic() { 138 result = append(result, llndkLsdumpTag) 139 } 140 if m.library.hasStubsVariants() { 141 result = append(result, apexLsdumpTag) 142 } 143 if headerAbiChecker.enabled() { 144 result = append(result, platformLsdumpTag) 145 } 146 } else if headerAbiChecker.enabled() { 147 if m.InProduct() { 148 result = append(result, productLsdumpTag) 149 } 150 if m.InVendor() { 151 result = append(result, vendorLsdumpTag) 152 } 153 } 154 return result 155} 156 157type shouldCreateAbiDumpContext interface { 158 android.ModuleProviderContext 159 Module() android.Module 160 Config() android.Config 161} 162 163var _ shouldCreateAbiDumpContext = android.ModuleContext(nil) 164var _ shouldCreateAbiDumpContext = android.OutgoingTransitionContext(nil) 165 166// Called from sabiTransitionMutator to check whether ABI dumps should be created for this module. 167// ctx should be wrapping a native library type module. 168func shouldCreateSourceAbiDumpForLibrary(ctx shouldCreateAbiDumpContext) bool { 169 m, ok := ctx.Module().(*Module) 170 if !ok { 171 return false 172 } 173 174 // Only generate ABI dump for device modules. 175 if !m.Device() { 176 return false 177 } 178 179 // Only create ABI dump for native library module types. 180 if m.library == nil { 181 return false 182 } 183 184 // Don't create ABI dump for static libraries 185 // The sabi variant will be propagated to dependencies of ABI checked libraries. 186 if m.library.static() { 187 return false 188 } 189 190 // Module is shared library type. 191 192 // Don't check uninstallable modules. 193 if m.IsHideFromMake() { 194 return false 195 } 196 197 // Don't check ramdisk or recovery variants. Only check core, vendor or product variants. 198 if m.InRamdisk() || m.InVendorRamdisk() || m.InRecovery() { 199 return false 200 } 201 202 // Don't create ABI dump for prebuilts. 203 if m.Prebuilt() != nil || m.IsSnapshotPrebuilt() { 204 return false 205 } 206 207 // Coverage builds have extra symbols. 208 if m.isCoverageVariant() { 209 return false 210 } 211 212 // Some sanitizer variants may have different ABI. 213 if m.sanitize != nil && !m.sanitize.isVariantOnProductionDevice() { 214 return false 215 } 216 217 // Don't create ABI dump for stubs. 218 if m.isNDKStubLibrary() || m.IsLlndk() || m.IsStubs() { 219 return false 220 } 221 222 apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) 223 if apexInfo.IsForPlatform() { 224 // Bionic libraries that are installed to the bootstrap directory are not ABI checked. 225 // Only the runtime APEX variants, which are the implementation libraries of bionic NDK stubs, 226 // are checked. 227 if InstallToBootstrap(m.BaseModuleName(), ctx.Config()) { 228 return false 229 } 230 } else { 231 // Don't create ABI dump if this library is for APEX but isn't exported. 232 if !m.HasStubsVariants() { 233 return false 234 } 235 } 236 return len(classifySourceAbiDump(m)) > 0 237} 238 239// Mark the direct and transitive dependencies of libraries that need ABI check, so that ABI dumps 240// of their dependencies would be generated. 241type sabiTransitionMutator struct{} 242 243func (s *sabiTransitionMutator) Split(ctx android.BaseModuleContext) []string { 244 return []string{""} 245} 246 247func (s *sabiTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string { 248 // Escape hatch to not check any ABI dump. 249 if ctx.Config().IsEnvTrue("SKIP_ABI_CHECKS") { 250 return "" 251 } 252 253 // Only create ABI dump for native shared libraries and their static library dependencies. 254 if m, ok := ctx.Module().(*Module); ok && m.sabi != nil { 255 if shouldCreateSourceAbiDumpForLibrary(ctx) { 256 if IsStaticDepTag(ctx.DepTag()) || ctx.DepTag() == reuseObjTag { 257 return "sabi" 258 } 259 } else if sourceVariation == "sabi" { 260 if IsWholeStaticLib(ctx.DepTag()) || ctx.DepTag() == reuseObjTag { 261 return "sabi" 262 } 263 } 264 } 265 266 return "" 267} 268 269func (s *sabiTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string { 270 if incomingVariation == "" { 271 return "" 272 } 273 274 if incomingVariation == "sabi" { 275 if m, ok := ctx.Module().(*Module); ok && m.sabi != nil { 276 return "sabi" 277 } 278 } 279 280 return "" 281} 282 283func (s *sabiTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) { 284 if m, ok := ctx.Module().(*Module); ok && m.sabi != nil { 285 if variation == "sabi" { 286 m.sabi.Properties.ShouldCreateSourceAbiDump = true 287 m.HideFromMake() 288 m.Properties.PreventInstall = true 289 } else if shouldCreateSourceAbiDumpForLibrary(ctx) { 290 // Escape hatch to not check any ABI dump. 291 if !ctx.Config().IsEnvTrue("SKIP_ABI_CHECKS") { 292 m.sabi.Properties.ShouldCreateSourceAbiDump = true 293 } 294 } 295 } 296} 297 298// Add an entry to the global list of lsdump. The list is exported to a Make variable by 299// `cc.makeVarsProvider`. 300func addLsdumpPath(config android.Config, lsdumpPath string) { 301 lsdumpPaths := lsdumpPaths(config) 302 lsdumpPathsLock.Lock() 303 defer lsdumpPathsLock.Unlock() 304 *lsdumpPaths = append(*lsdumpPaths, lsdumpPath) 305} 306