| // Copyright 2017 Google Inc. All rights reserved. | 
 | // | 
 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
 | // you may not use this file except in compliance with the License. | 
 | // You may obtain a copy of the License at | 
 | // | 
 | //     http://www.apache.org/licenses/LICENSE-2.0 | 
 | // | 
 | // Unless required by applicable law or agreed to in writing, software | 
 | // distributed under the License is distributed on an "AS IS" BASIS, | 
 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | // See the License for the specific language governing permissions and | 
 | // limitations under the License. | 
 |  | 
 | package cc | 
 |  | 
 | import ( | 
 | 	"strconv" | 
 |  | 
 | 	"github.com/google/blueprint" | 
 |  | 
 | 	"android/soong/android" | 
 | ) | 
 |  | 
 | type CoverageProperties struct { | 
 | 	Native_coverage *bool | 
 |  | 
 | 	NeedCoverageVariant bool `blueprint:"mutated"` | 
 | 	NeedCoverageBuild   bool `blueprint:"mutated"` | 
 |  | 
 | 	CoverageEnabled   bool `blueprint:"mutated"` | 
 | 	IsCoverageVariant bool `blueprint:"mutated"` | 
 | } | 
 |  | 
 | type coverage struct { | 
 | 	Properties CoverageProperties | 
 |  | 
 | 	// Whether binaries containing this module need --coverage added to their ldflags | 
 | 	linkCoverage bool | 
 | } | 
 |  | 
 | func (cov *coverage) props() []interface{} { | 
 | 	return []interface{}{&cov.Properties} | 
 | } | 
 |  | 
 | func getGcovProfileLibraryName(ctx ModuleContextIntf) string { | 
 | 	// This function should only ever be called for a cc.Module, so the | 
 | 	// following statement should always succeed. | 
 | 	if ctx.useSdk() { | 
 | 		return "libprofile-extras_ndk" | 
 | 	} else { | 
 | 		return "libprofile-extras" | 
 | 	} | 
 | } | 
 |  | 
 | func getClangProfileLibraryName(ctx ModuleContextIntf) string { | 
 | 	if ctx.useSdk() { | 
 | 		return "libprofile-clang-extras_ndk" | 
 | 	} else { | 
 | 		return "libprofile-clang-extras" | 
 | 	} | 
 | } | 
 |  | 
 | func (cov *coverage) deps(ctx DepsContext, deps Deps) Deps { | 
 | 	if cov.Properties.NeedCoverageVariant { | 
 | 		ctx.AddVariationDependencies([]blueprint.Variation{ | 
 | 			{Mutator: "link", Variation: "static"}, | 
 | 		}, coverageDepTag, getGcovProfileLibraryName(ctx)) | 
 | 		ctx.AddVariationDependencies([]blueprint.Variation{ | 
 | 			{Mutator: "link", Variation: "static"}, | 
 | 		}, coverageDepTag, getClangProfileLibraryName(ctx)) | 
 | 	} | 
 | 	return deps | 
 | } | 
 |  | 
 | func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) { | 
 | 	gcovCoverage := ctx.DeviceConfig().NativeCoverageEnabled() | 
 | 	clangCoverage := ctx.DeviceConfig().ClangCoverageEnabled() | 
 |  | 
 | 	if !gcovCoverage && !clangCoverage { | 
 | 		return flags, deps | 
 | 	} | 
 |  | 
 | 	if cov.Properties.CoverageEnabled { | 
 | 		cov.linkCoverage = true | 
 |  | 
 | 		if gcovCoverage { | 
 | 			flags.GcovCoverage = true | 
 | 			flags.Local.CommonFlags = append(flags.Local.CommonFlags, "--coverage", "-O0") | 
 |  | 
 | 			// Override -Wframe-larger-than and non-default optimization | 
 | 			// flags that the module may use. | 
 | 			flags.Local.CFlags = append(flags.Local.CFlags, "-Wno-frame-larger-than=", "-O0") | 
 | 		} else if clangCoverage { | 
 | 			flags.Local.CommonFlags = append(flags.Local.CommonFlags, "-fprofile-instr-generate", "-fcoverage-mapping") | 
 | 		} | 
 | 	} | 
 |  | 
 | 	// Even if we don't have coverage enabled, if any of our object files were compiled | 
 | 	// with coverage, then we need to add --coverage to our ldflags. | 
 | 	if !cov.linkCoverage { | 
 | 		if ctx.static() && !ctx.staticBinary() { | 
 | 			// For static libraries, the only thing that changes our object files | 
 | 			// are included whole static libraries, so check to see if any of | 
 | 			// those have coverage enabled. | 
 | 			ctx.VisitDirectDepsWithTag(wholeStaticDepTag, func(m android.Module) { | 
 | 				if cc, ok := m.(*Module); ok && cc.coverage != nil { | 
 | 					if cc.coverage.linkCoverage { | 
 | 						cov.linkCoverage = true | 
 | 					} | 
 | 				} | 
 | 			}) | 
 | 		} else { | 
 | 			// For executables and shared libraries, we need to check all of | 
 | 			// our static dependencies. | 
 | 			ctx.VisitDirectDeps(func(m android.Module) { | 
 | 				cc, ok := m.(*Module) | 
 | 				if !ok || cc.coverage == nil { | 
 | 					return | 
 | 				} | 
 |  | 
 | 				if static, ok := cc.linker.(libraryInterface); !ok || !static.static() { | 
 | 					return | 
 | 				} | 
 |  | 
 | 				if cc.coverage.linkCoverage { | 
 | 					cov.linkCoverage = true | 
 | 				} | 
 | 			}) | 
 | 		} | 
 | 	} | 
 |  | 
 | 	if cov.linkCoverage { | 
 | 		if gcovCoverage { | 
 | 			flags.Local.LdFlags = append(flags.Local.LdFlags, "--coverage") | 
 |  | 
 | 			coverage := ctx.GetDirectDepWithTag(getGcovProfileLibraryName(ctx), coverageDepTag).(*Module) | 
 | 			deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path()) | 
 |  | 
 | 			flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--wrap,getenv") | 
 | 		} else if clangCoverage { | 
 | 			flags.Local.LdFlags = append(flags.Local.LdFlags, "-fprofile-instr-generate") | 
 |  | 
 | 			coverage := ctx.GetDirectDepWithTag(getClangProfileLibraryName(ctx), coverageDepTag).(*Module) | 
 | 			deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path()) | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return flags, deps | 
 | } | 
 |  | 
 | func (cov *coverage) begin(ctx BaseModuleContext) { | 
 | 	// Coverage is disabled globally | 
 | 	if !ctx.DeviceConfig().NativeCoverageEnabled() && !ctx.DeviceConfig().ClangCoverageEnabled() { | 
 | 		return | 
 | 	} | 
 |  | 
 | 	var needCoverageVariant bool | 
 | 	var needCoverageBuild bool | 
 |  | 
 | 	if ctx.Host() { | 
 | 		// TODO(dwillemsen): because of -nodefaultlibs, we must depend on libclang_rt.profile-*.a | 
 | 		// Just turn off for now. | 
 | 	} else if !ctx.nativeCoverage() { | 
 | 		// Native coverage is not supported for this module type. | 
 | 	} else { | 
 | 		// Check if Native_coverage is set to false.  This property defaults to true. | 
 | 		needCoverageVariant = BoolDefault(cov.Properties.Native_coverage, true) | 
 | 		if sdk_version := ctx.sdkVersion(); ctx.useSdk() && sdk_version != "current" { | 
 | 			// Native coverage is not supported for SDK versions < 23 | 
 | 			if fromApi, err := strconv.Atoi(sdk_version); err == nil && fromApi < 23 { | 
 | 				needCoverageVariant = false | 
 | 			} | 
 | 		} | 
 |  | 
 | 		if needCoverageVariant { | 
 | 			// Coverage variant is actually built with coverage if enabled for its module path | 
 | 			needCoverageBuild = ctx.DeviceConfig().CoverageEnabledForPath(ctx.ModuleDir()) | 
 | 		} | 
 | 	} | 
 |  | 
 | 	cov.Properties.NeedCoverageBuild = needCoverageBuild | 
 | 	cov.Properties.NeedCoverageVariant = needCoverageVariant | 
 | } | 
 |  | 
 | // Coverage is an interface for non-CC modules to implement to be mutated for coverage | 
 | type Coverage interface { | 
 | 	android.Module | 
 | 	IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool | 
 | 	PreventInstall() | 
 | 	HideFromMake() | 
 | 	MarkAsCoverageVariant(bool) | 
 | } | 
 |  | 
 | func coverageMutator(mctx android.BottomUpMutatorContext) { | 
 | 	if c, ok := mctx.Module().(*Module); ok && c.coverage != nil { | 
 | 		needCoverageVariant := c.coverage.Properties.NeedCoverageVariant | 
 | 		needCoverageBuild := c.coverage.Properties.NeedCoverageBuild | 
 | 		if needCoverageVariant { | 
 | 			m := mctx.CreateVariations("", "cov") | 
 |  | 
 | 			// Setup the non-coverage version and set HideFromMake and | 
 | 			// PreventInstall to true. | 
 | 			m[0].(*Module).coverage.Properties.CoverageEnabled = false | 
 | 			m[0].(*Module).coverage.Properties.IsCoverageVariant = false | 
 | 			m[0].(*Module).Properties.HideFromMake = true | 
 | 			m[0].(*Module).Properties.PreventInstall = true | 
 |  | 
 | 			// The coverage-enabled version inherits HideFromMake, | 
 | 			// PreventInstall from the original module. | 
 | 			m[1].(*Module).coverage.Properties.CoverageEnabled = needCoverageBuild | 
 | 			m[1].(*Module).coverage.Properties.IsCoverageVariant = true | 
 | 		} | 
 | 	} else if cov, ok := mctx.Module().(Coverage); ok && cov.IsNativeCoverageNeeded(mctx) { | 
 | 		// APEX modules fall here | 
 |  | 
 | 		// Note: variant "" is also created because an APEX can be depended on by another | 
 | 		// module which are split into "" and "cov" variants. e.g. when cc_test refers | 
 | 		// to an APEX via 'data' property. | 
 | 		m := mctx.CreateVariations("", "cov") | 
 | 		m[0].(Coverage).MarkAsCoverageVariant(true) | 
 | 		m[0].(Coverage).PreventInstall() | 
 | 		m[0].(Coverage).HideFromMake() | 
 | 	} | 
 | } |