Merge "Don't remove entries for overriddable modules"
diff --git a/android/config.go b/android/config.go
index 0fe4a0c..16f3d73 100644
--- a/android/config.go
+++ b/android/config.go
@@ -406,6 +406,14 @@
return Config{}, err
}
+ if Bool(config.productVariables.GcovCoverage) && Bool(config.productVariables.ClangCoverage) {
+ return Config{}, fmt.Errorf("GcovCoverage and ClangCoverage cannot both be set")
+ }
+
+ config.productVariables.Native_coverage = proptools.BoolPtr(
+ Bool(config.productVariables.GcovCoverage) ||
+ Bool(config.productVariables.ClangCoverage))
+
return Config{config}, nil
}
@@ -712,10 +720,17 @@
return Bool(c.productVariables.Allow_missing_dependencies)
}
+// Returns true if building without full platform sources.
func (c *config) UnbundledBuild() bool {
return Bool(c.productVariables.Unbundled_build)
}
+// Returns true if building apps that aren't bundled with the platform.
+// UnbundledBuild() is always true when this is true.
+func (c *config) UnbundledBuildApps() bool {
+ return Bool(c.productVariables.Unbundled_build_apps)
+}
+
func (c *config) UnbundledBuildUsePrebuiltSdks() bool {
return Bool(c.productVariables.Unbundled_build) && !Bool(c.productVariables.Unbundled_build_sdks_from_source)
}
@@ -1029,27 +1044,55 @@
return Bool(c.config.productVariables.SamplingPGO)
}
-func (c *config) NativeLineCoverage() bool {
- return Bool(c.productVariables.NativeLineCoverage)
+// JavaCoverageEnabledForPath returns whether Java code coverage is enabled for
+// path. Coverage is enabled by default when the product variable
+// JavaCoveragePaths is empty. If JavaCoveragePaths is not empty, coverage is
+// enabled for any path which is part of this variable (and not part of the
+// JavaCoverageExcludePaths product variable). Value "*" in JavaCoveragePaths
+// represents any path.
+func (c *deviceConfig) JavaCoverageEnabledForPath(path string) bool {
+ coverage := false
+ if c.config.productVariables.JavaCoveragePaths == nil ||
+ InList("*", c.config.productVariables.JavaCoveragePaths) ||
+ HasAnyPrefix(path, c.config.productVariables.JavaCoveragePaths) {
+ coverage = true
+ }
+ if coverage && c.config.productVariables.JavaCoverageExcludePaths != nil {
+ if HasAnyPrefix(path, c.config.productVariables.JavaCoverageExcludePaths) {
+ coverage = false
+ }
+ }
+ return coverage
}
+// Returns true if gcov or clang coverage is enabled.
func (c *deviceConfig) NativeCoverageEnabled() bool {
- return Bool(c.config.productVariables.Native_coverage) || Bool(c.config.productVariables.NativeLineCoverage)
+ return Bool(c.config.productVariables.GcovCoverage) ||
+ Bool(c.config.productVariables.ClangCoverage)
}
func (c *deviceConfig) ClangCoverageEnabled() bool {
return Bool(c.config.productVariables.ClangCoverage)
}
-func (c *deviceConfig) CoverageEnabledForPath(path string) bool {
+func (c *deviceConfig) GcovCoverageEnabled() bool {
+ return Bool(c.config.productVariables.GcovCoverage)
+}
+
+// NativeCoverageEnabledForPath returns whether (GCOV- or Clang-based) native
+// code coverage is enabled for path. By default, coverage is not enabled for a
+// given path unless it is part of the NativeCoveragePaths product variable (and
+// not part of the NativeCoverageExcludePaths product variable). Value "*" in
+// NativeCoveragePaths represents any path.
+func (c *deviceConfig) NativeCoverageEnabledForPath(path string) bool {
coverage := false
- if c.config.productVariables.CoveragePaths != nil {
- if InList("*", c.config.productVariables.CoveragePaths) || HasAnyPrefix(path, c.config.productVariables.CoveragePaths) {
+ if c.config.productVariables.NativeCoveragePaths != nil {
+ if InList("*", c.config.productVariables.NativeCoveragePaths) || HasAnyPrefix(path, c.config.productVariables.NativeCoveragePaths) {
coverage = true
}
}
- if coverage && c.config.productVariables.CoverageExcludePaths != nil {
- if HasAnyPrefix(path, c.config.productVariables.CoverageExcludePaths) {
+ if coverage && c.config.productVariables.NativeCoverageExcludePaths != nil {
+ if HasAnyPrefix(path, c.config.productVariables.NativeCoverageExcludePaths) {
coverage = false
}
}
diff --git a/android/module.go b/android/module.go
index a488c0d..f24047c 100644
--- a/android/module.go
+++ b/android/module.go
@@ -835,6 +835,10 @@
return m.Os().Class == Host || m.Os().Class == HostCross
}
+func (m *ModuleBase) Device() bool {
+ return m.Os().Class == Device
+}
+
func (m *ModuleBase) Arch() Arch {
return m.Target().Arch
}
diff --git a/android/rule_builder.go b/android/rule_builder.go
index 6226548..afb5f4e 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -172,7 +172,7 @@
inputs := make(map[string]Path)
for _, c := range r.commands {
- for _, input := range c.inputs {
+ for _, input := range append(c.inputs, c.implicits...) {
inputStr := input.String()
if _, isOutput := outputs[inputStr]; !isOutput {
if _, isDepFile := depFiles[inputStr]; !isDepFile {
@@ -480,6 +480,7 @@
type RuleBuilderCommand struct {
buf strings.Builder
inputs Paths
+ implicits Paths
orderOnlys Paths
outputs WritablePaths
depFiles WritablePaths
@@ -503,6 +504,16 @@
return path.String()
}
+func (c *RuleBuilderCommand) addImplicit(path Path) string {
+ if c.sbox {
+ if rel, isRel, _ := maybeRelErr(c.sboxOutDir.String(), path.String()); isRel {
+ return "__SBOX_OUT_DIR__/" + rel
+ }
+ }
+ c.implicits = append(c.implicits, path)
+ return path.String()
+}
+
func (c *RuleBuilderCommand) addOrderOnly(path Path) {
c.orderOnlys = append(c.orderOnlys, path)
}
@@ -623,7 +634,7 @@
// Implicit adds the specified input path to the dependencies returned by RuleBuilder.Inputs without modifying the
// command line.
func (c *RuleBuilderCommand) Implicit(path Path) *RuleBuilderCommand {
- c.addInput(path)
+ c.addImplicit(path)
return c
}
@@ -631,11 +642,16 @@
// command line.
func (c *RuleBuilderCommand) Implicits(paths Paths) *RuleBuilderCommand {
for _, path := range paths {
- c.addInput(path)
+ c.addImplicit(path)
}
return c
}
+// GetImplicits returns the command's implicit inputs.
+func (c *RuleBuilderCommand) GetImplicits() Paths {
+ return c.implicits
+}
+
// OrderOnly adds the specified input path to the dependencies returned by RuleBuilder.OrderOnlys
// without modifying the command line.
func (c *RuleBuilderCommand) OrderOnly(path Path) *RuleBuilderCommand {
diff --git a/android/variable.go b/android/variable.go
index b69d425..2c8bd07 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -216,6 +216,7 @@
Allow_missing_dependencies *bool `json:",omitempty"`
Unbundled_build *bool `json:",omitempty"`
+ Unbundled_build_apps *bool `json:",omitempty"`
Unbundled_build_sdks_from_source *bool `json:",omitempty"`
Malloc_not_svelte *bool `json:",omitempty"`
Malloc_zero_contents *bool `json:",omitempty"`
@@ -266,11 +267,16 @@
SamplingPGO *bool `json:",omitempty"`
- NativeLineCoverage *bool `json:",omitempty"`
- Native_coverage *bool `json:",omitempty"`
- ClangCoverage *bool `json:",omitempty"`
- CoveragePaths []string `json:",omitempty"`
- CoverageExcludePaths []string `json:",omitempty"`
+ JavaCoveragePaths []string `json:",omitempty"`
+ JavaCoverageExcludePaths []string `json:",omitempty"`
+
+ GcovCoverage *bool `json:",omitempty"`
+ ClangCoverage *bool `json:",omitempty"`
+ NativeCoveragePaths []string `json:",omitempty"`
+ NativeCoverageExcludePaths []string `json:",omitempty"`
+
+ // Set by NewConfig
+ Native_coverage *bool
SanitizeHost []string `json:",omitempty"`
SanitizeDevice []string `json:",omitempty"`
diff --git a/androidmk/androidmk/androidmk.go b/androidmk/androidmk/androidmk.go
index 9d0c3ac..dcd67d8 100644
--- a/androidmk/androidmk/androidmk.go
+++ b/androidmk/androidmk/androidmk.go
@@ -34,6 +34,7 @@
defs []bpparser.Definition
localAssignments map[string]*bpparser.Property
globalAssignments map[string]*bpparser.Expression
+ variableRenames map[string]string
scope mkparser.Scope
module *bpparser.Module
@@ -43,6 +44,10 @@
inModule bool
}
+var invalidVariableStringToReplacement = map[string]string{
+ "-": "_dash_",
+}
+
func (f *bpFile) insertComment(s string) {
f.comments = append(f.comments, &bpparser.CommentGroup{
Comments: []*bpparser.Comment{
@@ -120,10 +125,12 @@
scope: androidScope(),
localAssignments: make(map[string]*bpparser.Property),
globalAssignments: make(map[string]*bpparser.Expression),
+ variableRenames: make(map[string]string),
}
var conds []*conditional
var assignmentCond *conditional
+ var tree *bpparser.File
for _, node := range nodes {
file.setMkPos(p.Unpack(node.Pos()), p.Unpack(node.End()))
@@ -200,24 +207,46 @@
}
}
- tree := &bpparser.File{
+ tree = &bpparser.File{
Defs: file.defs,
Comments: file.comments,
}
// check for common supported but undesirable structures and clean them up
fixer := bpfix.NewFixer(tree)
- tree, err := fixer.Fix(bpfix.NewFixRequest().AddAll())
- if err != nil {
- return "", []error{err}
+ fixedTree, fixerErr := fixer.Fix(bpfix.NewFixRequest().AddAll())
+ if fixerErr != nil {
+ errs = append(errs, fixerErr)
+ } else {
+ tree = fixedTree
}
out, err := bpparser.Print(tree)
if err != nil {
- return "", []error{err}
+ errs = append(errs, err)
+ return "", errs
}
- return string(out), nil
+ return string(out), errs
+}
+
+func renameVariableWithInvalidCharacters(name string) string {
+ renamed := ""
+ for invalid, replacement := range invalidVariableStringToReplacement {
+ if strings.Contains(name, invalid) {
+ renamed = strings.ReplaceAll(name, invalid, replacement)
+ }
+ }
+
+ return renamed
+}
+
+func invalidVariableStrings() string {
+ invalidStrings := make([]string, 0, len(invalidVariableStringToReplacement))
+ for s := range invalidVariableStringToReplacement {
+ invalidStrings = append(invalidStrings, "\""+s+"\"")
+ }
+ return strings.Join(invalidStrings, ", ")
}
func handleAssignment(file *bpFile, assignment *mkparser.Assignment, c *conditional) {
@@ -234,6 +263,12 @@
name := assignment.Name.Value(nil)
prefix := ""
+ if newName := renameVariableWithInvalidCharacters(name); newName != "" {
+ file.warnf("Variable names cannot contain: %s. Renamed \"%s\" to \"%s\"", invalidVariableStrings(), name, newName)
+ file.variableRenames[name] = newName
+ name = newName
+ }
+
if strings.HasPrefix(name, "LOCAL_") {
for _, x := range propertyPrefixes {
if strings.HasSuffix(name, "_"+x.mk) {
@@ -337,11 +372,11 @@
var err error
switch typ {
case bpparser.ListType:
- exp, err = makeToListExpression(val, file.scope)
+ exp, err = makeToListExpression(val, file)
case bpparser.StringType:
- exp, err = makeToStringExpression(val, file.scope)
+ exp, err = makeToStringExpression(val, file)
case bpparser.BoolType:
- exp, err = makeToBoolExpression(val)
+ exp, err = makeToBoolExpression(val, file)
default:
panic("unknown type")
}
@@ -354,7 +389,6 @@
}
func setVariable(file *bpFile, plusequals bool, prefix, name string, value bpparser.Expression, local bool) error {
-
if prefix != "" {
name = prefix + "." + name
}
diff --git a/androidmk/androidmk/androidmk_test.go b/androidmk/androidmk/androidmk_test.go
index 54bd586..4f307c4 100644
--- a/androidmk/androidmk/androidmk_test.go
+++ b/androidmk/androidmk/androidmk_test.go
@@ -1367,6 +1367,28 @@
`,
},
{
+ desc: "dashed_variable gets renamed",
+ in: `
+ include $(CLEAR_VARS)
+
+ dashed-variable:= a.cpp
+
+ LOCAL_MODULE:= test
+ LOCAL_SRC_FILES:= $(dashed-variable)
+ include $(BUILD_EXECUTABLE)
+ `,
+ expected: `
+
+// ANDROIDMK TRANSLATION WARNING: Variable names cannot contain: "-". Renamed "dashed-variable" to "dashed_dash_variable"
+dashed_dash_variable = ["a.cpp"]
+cc_binary {
+
+ name: "test",
+ srcs: dashed_dash_variable,
+}
+`,
+ },
+ {
desc: "undefined_boolean_var",
in: `
include $(CLEAR_VARS)
diff --git a/androidmk/androidmk/values.go b/androidmk/androidmk/values.go
index 6b18a65..9618142 100644
--- a/androidmk/androidmk/values.go
+++ b/androidmk/androidmk/values.go
@@ -60,8 +60,7 @@
}, nil
}
-func makeToStringExpression(ms *mkparser.MakeString, scope mkparser.Scope) (bpparser.Expression, error) {
-
+func makeToStringExpression(ms *mkparser.MakeString, file *bpFile) (bpparser.Expression, error) {
var val bpparser.Expression
var err error
@@ -70,18 +69,18 @@
}
for i, s := range ms.Strings[1:] {
- if ret, ok := ms.Variables[i].EvalFunction(scope); ok {
+ if ret, ok := ms.Variables[i].EvalFunction(file.scope); ok {
if len(ret) > 1 {
return nil, fmt.Errorf("Unexpected list value %s", ms.Dump())
}
val, err = addValues(val, stringToStringValue(ret[0]))
} else {
- name := ms.Variables[i].Name
- if !name.Const() {
- return nil, fmt.Errorf("Unsupported non-const variable name %s", name.Dump())
+ name, err := extractVariableName(ms.Variables[i].Name, file)
+ if err != nil {
+ return nil, err
}
tmp := &bpparser.Variable{
- Name: name.Value(nil),
+ Name: name,
Value: &bpparser.String{},
}
@@ -125,8 +124,7 @@
}
-func makeToListExpression(ms *mkparser.MakeString, scope mkparser.Scope) (bpparser.Expression, error) {
-
+func makeToListExpression(ms *mkparser.MakeString, file *bpFile) (bpparser.Expression, error) {
fields := ms.Split(" \t")
var listOfListValues []bpparser.Expression
@@ -135,14 +133,14 @@
for _, f := range fields {
if len(f.Variables) == 1 && f.Strings[0] == "" && f.Strings[1] == "" {
- if ret, ok := f.Variables[0].EvalFunction(scope); ok {
+ if ret, ok := f.Variables[0].EvalFunction(file.scope); ok {
listValue.Values = append(listValue.Values, stringListToStringValueList(ret)...)
} else {
- // Variable by itself, variable is probably a list
- if !f.Variables[0].Name.Const() {
- return nil, fmt.Errorf("unsupported non-const variable name")
+ name, err := extractVariableName(f.Variables[0].Name, file)
+ if err != nil {
+ return nil, err
}
- if f.Variables[0].Name.Value(nil) == "TOP" {
+ if name == "TOP" {
listValue.Values = append(listValue.Values, &bpparser.String{
Value: ".",
})
@@ -151,14 +149,14 @@
listOfListValues = append(listOfListValues, listValue)
}
listOfListValues = append(listOfListValues, &bpparser.Variable{
- Name: f.Variables[0].Name.Value(nil),
+ Name: name,
Value: &bpparser.List{},
})
listValue = &bpparser.List{}
}
}
} else {
- s, err := makeToStringExpression(f, scope)
+ s, err := makeToStringExpression(f, file)
if err != nil {
return nil, err
}
@@ -208,15 +206,15 @@
}, nil
}
-func makeToBoolExpression(ms *mkparser.MakeString) (bpparser.Expression, error) {
+func makeToBoolExpression(ms *mkparser.MakeString, file *bpFile) (bpparser.Expression, error) {
if !ms.Const() {
if len(ms.Variables) == 1 && ms.Strings[0] == "" && ms.Strings[1] == "" {
- name := ms.Variables[0].Name
- if !name.Const() {
- return nil, fmt.Errorf("unsupported non-const variable name")
+ name, err := extractVariableName(ms.Variables[0].Name, file)
+ if err != nil {
+ return nil, err
}
return &bpparser.Variable{
- Name: name.Value(nil),
+ Name: name,
Value: &bpparser.Bool{},
}, nil
} else {
@@ -226,3 +224,17 @@
return stringToBoolValue(ms.Value(nil))
}
+
+func extractVariableName(name *mkparser.MakeString, file *bpFile) (string, error) {
+ if !name.Const() {
+ return "", fmt.Errorf("Unsupported non-const variable name %s", name.Dump())
+ }
+
+ variableName := name.Value(nil)
+
+ if newName, ok := file.variableRenames[variableName]; ok {
+ variableName = newName
+ }
+
+ return variableName, nil
+}
diff --git a/androidmk/cmd/androidmk.go b/androidmk/cmd/androidmk.go
index 00488eb..d2f4324 100644
--- a/androidmk/cmd/androidmk.go
+++ b/androidmk/cmd/androidmk.go
@@ -45,12 +45,13 @@
}
output, errs := androidmk.ConvertFile(os.Args[1], bytes.NewBuffer(b))
+ if len(output) > 0 {
+ fmt.Print(output)
+ }
if len(errs) > 0 {
for _, err := range errs {
fmt.Fprintln(os.Stderr, "ERROR: ", err)
}
os.Exit(1)
}
-
- fmt.Print(output)
}
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 774b62d..4dd14d8 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -184,7 +184,7 @@
// we need to remove the suffix from LOCAL_MODULE_STEM, otherwise
// we will have foo.jar.jar
fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", strings.TrimSuffix(fi.Stem(), ".jar"))
- if javaModule, ok := fi.module.(java.Dependency); ok {
+ if javaModule, ok := fi.module.(java.ApexDependency); ok {
fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", javaModule.ImplementationAndResourcesJars()[0].String())
fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", javaModule.HeaderJars()[0].String())
} else {
@@ -233,8 +233,9 @@
for _, o := range a.overridableProperties.Overrides {
patterns = append(patterns, "%."+o+a.suffix)
}
- fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES :=", strings.Join(patterns, " "))
-
+ if len(patterns) > 0 {
+ fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES :=", strings.Join(patterns, " "))
+ }
if len(a.compatSymlinks) > 0 {
// For flattened apexes, compat symlinks are attached to apex_manifest.json which is guaranteed for every apex
postInstallCommands = append(postInstallCommands, a.compatSymlinks...)
@@ -307,7 +308,9 @@
fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", a.installDir.ToMakePath().String())
fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", name+apexType.suffix())
fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !a.installable())
- fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES :=", strings.Join(a.overridableProperties.Overrides, " "))
+ if len(a.overridableProperties.Overrides) > 0 {
+ fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES :=", strings.Join(a.overridableProperties.Overrides, " "))
+ }
if len(moduleNames) > 0 {
fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(moduleNames, " "))
}
diff --git a/apex/apex.go b/apex/apex.go
index 3fef1ee..58cbb13 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -178,12 +178,6 @@
//
// Module separator
//
- m["com.android.conscrypt"] = []string{
- "libnativehelper_header_only",
- }
- //
- // Module separator
- //
m["com.android.neuralnetworks"] = []string{
"android.hardware.neuralnetworks@1.0",
"android.hardware.neuralnetworks@1.1",
@@ -375,7 +369,6 @@
"libbinderthreadstateutils",
"libbluetooth-types-header",
"libbufferhub_headers",
- "libc_scudo",
"libcodec2",
"libcodec2_headers",
"libcodec2_hidl@1.0",
@@ -479,7 +472,6 @@
"libbase_ndk",
"libfuse",
"libfuse_jni",
- "libnativehelper_header_only",
}
//
// Module separator
@@ -561,7 +553,6 @@
"ipmemorystore-aidl-interfaces-java",
"libcgrouprc",
"libcgrouprc_format",
- "libnativehelper_compat_libc++",
"libtetherutilsjni",
"libvndksupport",
"net-utils-framework-common",
@@ -993,9 +984,6 @@
// List of providing APEXes' names so that this APEX can depend on provided shared libraries.
Uses []string
- // A txt file containing list of files that are allowed to be included in this APEX.
- Whitelisted_files *string
-
// package format of this apex variant; could be non-flattened, flattened, or zip.
// imageApex, zipApex or flattened
ApexType apexPackaging `blueprint:"mutated"`
@@ -1071,6 +1059,9 @@
// Apex Container Package Name.
// Override value for attribute package:name in AndroidManifest.xml
Package_name string
+
+ // A txt file containing list of files that are allowed to be included in this APEX.
+ Allowed_files *string `android:"path"`
}
type apexPackaging int
@@ -1462,6 +1453,9 @@
}
func (a *apexBundle) OverridablePropertiesDepsMutator(ctx android.BottomUpMutatorContext) {
+ if a.overridableProperties.Allowed_files != nil {
+ android.ExtractSourceDeps(ctx, a.overridableProperties.Allowed_files)
+ }
ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(),
androidAppTag, a.overridableProperties.Apps...)
ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(),
@@ -1561,7 +1555,7 @@
var _ cc.Coverage = (*apexBundle)(nil)
func (a *apexBundle) IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool {
- return ctx.Device() && (ctx.DeviceConfig().NativeCoverageEnabled() || ctx.DeviceConfig().ClangCoverageEnabled())
+ return ctx.Device() && ctx.DeviceConfig().NativeCoverageEnabled()
}
func (a *apexBundle) PreventInstall() {
@@ -1660,7 +1654,9 @@
func apexFileForJavaLibrary(ctx android.BaseModuleContext, lib javaDependency, module android.Module) apexFile {
dirInApex := "javalib"
fileToCopy := lib.DexJarBuildPath()
- af := newApexFile(ctx, fileToCopy, module.Name(), dirInApex, javaSharedLib, module)
+ // Remove prebuilt_ if necessary so the source and prebuilt modules have the same name.
+ name := strings.TrimPrefix(module.Name(), "prebuilt_")
+ af := newApexFile(ctx, fileToCopy, name, dirInApex, javaSharedLib, module)
af.jacocoReportClassesFile = lib.JacocoReportClassesFile()
af.stem = lib.Stem() + ".jar"
return af
@@ -1954,8 +1950,10 @@
fi := apexFileForNativeLibrary(ctx, c, handleSpecialLibs)
fi.isJniLib = isJniLib
filesInfo = append(filesInfo, fi)
- // bootstrap bionic libs are treated as provided by system
- if c.HasStubsVariants() && !cc.InstallToBootstrap(c.BaseModuleName(), ctx.Config()) {
+ // Collect the list of stub-providing libs except:
+ // - VNDK libs are only for vendors
+ // - bootstrap bionic libs are treated as provided by system
+ if c.HasStubsVariants() && !a.vndkApex && !cc.InstallToBootstrap(c.BaseModuleName(), ctx.Config()) {
provideNativeLibs = append(provideNativeLibs, fi.Stem())
}
return true // track transitive dependencies
@@ -1981,7 +1979,7 @@
}
case javaLibTag:
switch child.(type) {
- case *java.Library, *java.SdkLibrary, *java.DexImport:
+ case *java.Library, *java.SdkLibrary, *java.DexImport, *java.SdkLibraryImport:
af := apexFileForJavaLibrary(ctx, child.(javaDependency), child.(android.Module))
if !af.Ok() {
ctx.PropertyErrorf("java_libs", "%q is not configured to be compiled into dex", depName)
diff --git a/apex/apex_test.go b/apex/apex_test.go
index eef6f42..38c8489 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -66,7 +66,7 @@
func testApex(t *testing.T, bp string, handlers ...testCustomizer) (*android.TestContext, android.Config) {
t.Helper()
ctx, config := testApexContext(t, bp, handlers...)
- _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ _, errs := ctx.ParseBlueprintsFiles(".")
android.FailIfErrored(t, errs)
_, errs = ctx.PrepareBuildActions(config)
android.FailIfErrored(t, errs)
@@ -217,6 +217,11 @@
}
ctx := android.NewTestArchContext()
+
+ // from android package
+ android.RegisterPackageBuildComponents(ctx)
+ ctx.PreArchMutators(android.RegisterVisibilityRuleChecker)
+
ctx.RegisterModuleType("apex", BundleFactory)
ctx.RegisterModuleType("apex_test", testApexBundleFactory)
ctx.RegisterModuleType("apex_vndk", vndkApexBundleFactory)
@@ -230,6 +235,12 @@
ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators)
cc.RegisterRequiredBuildComponentsForTest(ctx)
+
+ // Register this after the prebuilt mutators have been registered (in
+ // cc.RegisterRequiredBuildComponentsForTest) to match what happens at runtime.
+ ctx.PreArchMutators(android.RegisterVisibilityRuleGatherer)
+ ctx.PostDepsMutators(android.RegisterVisibilityRuleEnforcer)
+
ctx.RegisterModuleType("cc_test", cc.TestFactory)
ctx.RegisterModuleType("vndk_prebuilt_shared", cc.VndkPrebuiltSharedFactory)
ctx.RegisterModuleType("vndk_libraries_txt", cc.VndkLibrariesTxtFactory)
@@ -240,7 +251,7 @@
java.RegisterJavaBuildComponents(ctx)
java.RegisterSystemModulesBuildComponents(ctx)
java.RegisterAppBuildComponents(ctx)
- ctx.RegisterModuleType("java_sdk_library", java.SdkLibraryFactory)
+ java.RegisterSdkLibraryBuildComponents(ctx)
ctx.RegisterSingletonType("apex_keys_text", apexKeysTextFactory)
ctx.PreDepsMutators(RegisterPreDepsMutators)
@@ -2817,6 +2828,40 @@
})
}
+func TestVndkApexShouldNotProvideNativeLibs(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex_vndk {
+ name: "myapex",
+ key: "myapex.key",
+ file_contexts: ":myapex-file_contexts",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libz",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ stubs: {
+ symbol_file: "libz.map.txt",
+ versions: ["30"],
+ }
+ }
+ `+vndkLibrariesTxtFiles("current"), withFiles(map[string][]byte{
+ "libz.map.txt": nil,
+ }))
+
+ apexManifestRule := ctx.ModuleForTests("myapex", "android_common_image").Rule("apexManifestRule")
+ provideNativeLibs := names(apexManifestRule.Args["provideNativeLibs"])
+ ensureListEmpty(t, provideNativeLibs)
+}
+
func TestDependenciesInApexManifest(t *testing.T) {
ctx, _ := testApex(t, `
apex {
@@ -4332,6 +4377,9 @@
"api/system-removed.txt": nil,
"api/test-current.txt": nil,
"api/test-removed.txt": nil,
+
+ // For java_sdk_library_import
+ "a.jar": nil,
}
func TestJavaSDKLibrary(t *testing.T) {
@@ -4458,6 +4506,117 @@
}
}
+func TestJavaSDKLibrary_ImportPreferred(t *testing.T) {
+ ctx, _ := testApex(t, ``,
+ withFiles(map[string][]byte{
+ "apex/a.java": nil,
+ "apex/apex_manifest.json": nil,
+ "apex/Android.bp": []byte(`
+ package {
+ default_visibility: ["//visibility:private"],
+ }
+
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ java_libs: ["foo", "bar"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ java_library {
+ name: "bar",
+ srcs: ["a.java"],
+ libs: ["foo"],
+ apex_available: ["myapex"],
+ sdk_version: "none",
+ system_modules: "none",
+ }
+`),
+ "source/a.java": nil,
+ "source/api/current.txt": nil,
+ "source/api/removed.txt": nil,
+ "source/Android.bp": []byte(`
+ package {
+ default_visibility: ["//visibility:private"],
+ }
+
+ java_sdk_library {
+ name: "foo",
+ visibility: ["//apex"],
+ srcs: ["a.java"],
+ api_packages: ["foo"],
+ apex_available: ["myapex"],
+ sdk_version: "none",
+ system_modules: "none",
+ public: {
+ enabled: true,
+ },
+ }
+`),
+ "prebuilt/a.jar": nil,
+ "prebuilt/Android.bp": []byte(`
+ package {
+ default_visibility: ["//visibility:private"],
+ }
+
+ java_sdk_library_import {
+ name: "foo",
+ visibility: ["//apex", "//source"],
+ apex_available: ["myapex"],
+ prefer: true,
+ public: {
+ jars: ["a.jar"],
+ },
+ }
+`),
+ }),
+ )
+
+ // java_sdk_library installs both impl jar and permission XML
+ ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+ "javalib/bar.jar",
+ "javalib/foo.jar",
+ "etc/permissions/foo.xml",
+ })
+
+ // The bar library should depend on the implementation jar.
+ barLibrary := ctx.ModuleForTests("bar", "android_common_myapex").Rule("javac")
+ if expected, actual := `^-classpath /[^:]*/turbine-combined/foo\.impl\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) {
+ t.Errorf("expected %q, found %#q", expected, actual)
+ }
+}
+
+func TestJavaSDKLibrary_ImportOnly(t *testing.T) {
+ testApexError(t, `java_libs: "foo" is not configured to be compiled into dex`, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ java_libs: ["foo"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ java_sdk_library_import {
+ name: "foo",
+ apex_available: ["myapex"],
+ prefer: true,
+ public: {
+ jars: ["a.jar"],
+ },
+ }
+
+ `, withFiles(filesForSdkLibrary))
+}
+
func TestCompatConfig(t *testing.T) {
ctx, _ := testApex(t, `
apex {
@@ -5237,6 +5396,61 @@
ensureContains(t, content, `name="myapex.apex" public_key="PRESIGNED" private_key="PRESIGNED" container_certificate="PRESIGNED" container_private_key="PRESIGNED" partition="system"`)
}
+func TestAllowedFiles(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ apps: ["app"],
+ allowed_files: "allowed.txt",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ android_app {
+ name: "app",
+ srcs: ["foo/bar/MyClass.java"],
+ package_name: "foo",
+ sdk_version: "none",
+ system_modules: "none",
+ apex_available: [ "myapex" ],
+ }
+ `, withFiles(map[string][]byte{
+ "sub/Android.bp": []byte(`
+ override_apex {
+ name: "override_myapex",
+ base: "myapex",
+ apps: ["override_app"],
+ allowed_files: ":allowed",
+ }
+ // Overridable "path" property should be referenced indirectly
+ filegroup {
+ name: "allowed",
+ srcs: ["allowed.txt"],
+ }
+ override_android_app {
+ name: "override_app",
+ base: "app",
+ package_name: "bar",
+ }
+ `),
+ }))
+
+ rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("diffApexContentRule")
+ if expected, actual := "allowed.txt", rule.Args["allowed_files_file"]; expected != actual {
+ t.Errorf("allowed_files_file: expected %q but got %q", expected, actual)
+ }
+
+ rule2 := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex_image").Rule("diffApexContentRule")
+ if expected, actual := "sub/allowed.txt", rule2.Args["allowed_files_file"]; expected != actual {
+ t.Errorf("allowed_files_file: expected %q but got %q", expected, actual)
+ }
+}
+
func TestMain(m *testing.M) {
run := func() int {
setUp()
diff --git a/apex/builder.go b/apex/builder.go
index 1293588..af43417 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -391,7 +391,7 @@
emitCommands = append(emitCommands, "sort -o "+imageContentFile.String()+" "+imageContentFile.String())
implicitInputs = append(implicitInputs, a.manifestPbOut)
- if a.properties.Whitelisted_files != nil {
+ if a.overridableProperties.Allowed_files != nil {
ctx.Build(pctx, android.BuildParams{
Rule: emitApexContentRule,
Implicits: implicitInputs,
@@ -402,7 +402,7 @@
},
})
implicitInputs = append(implicitInputs, imageContentFile)
- allowedFilesFile := android.PathForModuleSrc(ctx, proptools.String(a.properties.Whitelisted_files))
+ allowedFilesFile := android.PathForModuleSrc(ctx, proptools.String(a.overridableProperties.Allowed_files))
phonyOutput := android.PathForModuleOut(ctx, a.Name()+"-diff-phony-output")
ctx.Build(pctx, android.BuildParams{
diff --git a/apex/vndk_test.go b/apex/vndk_test.go
index 05cdfcd..60b6ed5 100644
--- a/apex/vndk_test.go
+++ b/apex/vndk_test.go
@@ -118,6 +118,7 @@
t.Run("VNDK APEX supports coverage variants", func(t *testing.T) {
ctx, _ := testApex(t, bp, func(fs map[string][]byte, config android.Config) {
+ config.TestProductVariables.GcovCoverage = proptools.BoolPtr(true)
config.TestProductVariables.Native_coverage = proptools.BoolPtr(true)
})
diff --git a/cc/cc.go b/cc/cc.go
index f80c229..ebdb46c 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -3099,10 +3099,19 @@
}
} else if vendorSpecific && String(m.Properties.Sdk_version) == "" {
// This will be available in /vendor (or /odm) only
- // We assume that modules under proprietary paths are compatible for
- // BOARD_VNDK_VERSION. The other modules are regarded as AOSP, or
- // PLATFORM_VNDK_VERSION.
- if isVendorProprietaryPath(mctx.ModuleDir()) {
+
+ // kernel_headers is a special module type whose exported headers
+ // are coming from DeviceKernelHeaders() which is always vendor
+ // dependent. They'll always have both vendor variants.
+ // For other modules, we assume that modules under proprietary
+ // paths are compatible for BOARD_VNDK_VERSION. The other modules
+ // are regarded as AOSP, which is PLATFORM_VNDK_VERSION.
+ if _, ok := m.linker.(*kernelHeadersDecorator); ok {
+ vendorVariants = append(vendorVariants,
+ platformVndkVersion,
+ boardVndkVersion,
+ )
+ } else if isVendorProprietaryPath(mctx.ModuleDir()) {
vendorVariants = append(vendorVariants, boardVndkVersion)
} else {
vendorVariants = append(vendorVariants, platformVndkVersion)
@@ -3200,6 +3209,10 @@
}
}
+func (c *Module) IsSdkVariant() bool {
+ return c.Properties.IsSdkVariant
+}
+
func getCurrentNdkPrebuiltVersion(ctx DepsContext) string {
if ctx.Config().PlatformSdkVersionInt() > config.NdkMaxPrebuiltVersionInt {
return strconv.Itoa(config.NdkMaxPrebuiltVersionInt)
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 76b4e38..f73e021 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -430,6 +430,40 @@
checkVndkLibrariesOutput(t, ctx, "vndkcorevariant.libraries.txt", nil)
}
+func TestVndkWithHostSupported(t *testing.T) {
+ ctx := testCc(t, `
+ cc_library {
+ name: "libvndk_host_supported",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ host_supported: true,
+ }
+
+ cc_library {
+ name: "libvndk_host_supported_but_disabled_on_device",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ host_supported: true,
+ enabled: false,
+ target: {
+ host: {
+ enabled: true,
+ }
+ }
+ }
+
+ vndk_libraries_txt {
+ name: "vndkcore.libraries.txt",
+ }
+ `)
+
+ checkVndkLibrariesOutput(t, ctx, "vndkcore.libraries.txt", []string{"libvndk_host_supported.so"})
+}
+
func TestVndkLibrariesTxtAndroidMk(t *testing.T) {
bp := `
vndk_libraries_txt {
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index 9383463..62d8cc8 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -32,7 +32,7 @@
"-march=armv8-a",
},
"armv8-2a": []string{
- "-march=armv8.2a",
+ "-march=armv8.2-a",
},
}
diff --git a/cc/coverage.go b/cc/coverage.go
index f885fcb..c823324 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -74,8 +74,8 @@
}
func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) {
- gcovCoverage := ctx.DeviceConfig().NativeCoverageEnabled()
clangCoverage := ctx.DeviceConfig().ClangCoverageEnabled()
+ gcovCoverage := ctx.DeviceConfig().GcovCoverageEnabled()
if !gcovCoverage && !clangCoverage {
return flags, deps
@@ -161,7 +161,7 @@
func SetCoverageProperties(ctx android.BaseModuleContext, properties CoverageProperties, moduleTypeHasCoverage bool,
useSdk bool, sdkVersion string) CoverageProperties {
// Coverage is disabled globally
- if !ctx.DeviceConfig().NativeCoverageEnabled() && !ctx.DeviceConfig().ClangCoverageEnabled() {
+ if !ctx.DeviceConfig().NativeCoverageEnabled() {
return properties
}
@@ -180,7 +180,7 @@
if needCoverageVariant {
// Coverage variant is actually built with coverage if enabled for its module path
- needCoverageBuild = ctx.DeviceConfig().CoverageEnabledForPath(ctx.ModuleDir())
+ needCoverageBuild = ctx.DeviceConfig().NativeCoverageEnabledForPath(ctx.ModuleDir())
}
}
diff --git a/cc/library.go b/cc/library.go
index ba8b0f4..968702e 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -1077,9 +1077,14 @@
func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objects, fileName string, soFile android.Path) {
if library.shouldCreateSourceAbiDump(ctx) {
- vndkVersion := ctx.DeviceConfig().PlatformVndkVersion()
- if ver := ctx.DeviceConfig().VndkVersion(); ver != "" && ver != "current" {
- vndkVersion = ver
+ var vndkVersion string
+
+ if ctx.useVndk() {
+ // For modules linking against vndk, follow its vndk version
+ vndkVersion = ctx.Module().(*Module).VndkVersion()
+ } else {
+ // Regard the other modules as PLATFORM_VNDK_VERSION
+ vndkVersion = ctx.DeviceConfig().PlatformVndkVersion()
}
exportIncludeDirs := library.flagExporter.exportedIncludes(ctx)
@@ -1575,7 +1580,8 @@
// (which is unnamed) and zero or more stubs variants.
func VersionMutator(mctx android.BottomUpMutatorContext) {
if library, ok := mctx.Module().(LinkableInterface); ok && VersionVariantAvailable(library) {
- if library.CcLibrary() && library.BuildSharedVariant() && len(library.StubsVersions()) > 0 {
+ if library.CcLibrary() && library.BuildSharedVariant() && len(library.StubsVersions()) > 0 &&
+ !library.IsSdkVariant() {
versions := library.StubsVersions()
normalizeVersions(mctx, versions)
if mctx.Failed() {
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index a7a1de2..4410302 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -124,6 +124,14 @@
if stl != nil {
pbm.AddProperty("stl", proptools.String(stl))
}
+
+ if lib, ok := ccModule.linker.(*libraryDecorator); ok {
+ uhs := lib.Properties.Unique_host_soname
+ if uhs != nil {
+ pbm.AddProperty("unique_host_soname", proptools.Bool(uhs))
+ }
+ }
+
return pbm
}
diff --git a/cc/linkable.go b/cc/linkable.go
index de36f90..66b1c3f 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -56,6 +56,7 @@
SdkVersion() string
AlwaysSdk() bool
+ IsSdkVariant() bool
ToolchainLibrary() bool
NdkPrebuiltStl() bool
diff --git a/cc/linker.go b/cc/linker.go
index c9cbd9b..58f8a29 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -298,17 +298,6 @@
}
}
- if inList("libc_scudo", deps.SharedLibs) {
- // libc_scudo is an alternate implementation of all
- // allocation functions (malloc, free), that uses
- // the scudo allocator instead of the default native
- // allocator. If this library is in the list, make
- // sure it's first so it properly overrides the
- // allocation functions of all other shared libraries.
- _, deps.SharedLibs = removeFromList("libc_scudo", deps.SharedLibs)
- deps.SharedLibs = append([]string{"libc_scudo"}, deps.SharedLibs...)
- }
-
// If libc and libdl are both in system_shared_libs make sure libdl comes after libc
// to avoid loading libdl before libc.
if inList("libdl", systemSharedLibs) && inList("libc", systemSharedLibs) &&
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index d79badb..5ef9a78 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -329,6 +329,7 @@
Description: "parse ndk api symbol file for api coverage: " + symbolFilePath.Rel(),
Outputs: []android.WritablePath{parsedApiCoveragePath},
Input: symbolFilePath,
+ Implicits: []android.Path{apiLevelsJson},
Args: map[string]string{
"apiMap": apiLevelsJson.String(),
},
diff --git a/cc/sanitize.go b/cc/sanitize.go
index aaaf694..72ad6d7 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -408,16 +408,6 @@
return deps
}
- if ctx.Device() {
- if Bool(sanitize.Properties.Sanitize.Address) {
- // Compiling asan and having libc_scudo in the same
- // executable will cause the executable to crash.
- // Remove libc_scudo since it is only used to override
- // allocation functions which asan already overrides.
- _, deps.SharedLibs = removeFromList("libc_scudo", deps.SharedLibs)
- }
- }
-
return deps
}
diff --git a/cc/sdk.go b/cc/sdk.go
index a6f94af..b68baad 100644
--- a/cc/sdk.go
+++ b/cc/sdk.go
@@ -41,7 +41,7 @@
modules[0].(*Module).Properties.Sdk_version = nil
modules[1].(*Module).Properties.IsSdkVariant = true
- if ctx.Config().UnbundledBuild() {
+ if ctx.Config().UnbundledBuildApps() {
modules[0].(*Module).Properties.HideFromMake = true
modules[0].(*Module).Properties.PreventInstall = true
} else {
diff --git a/cc/test.go b/cc/test.go
index 2439c94..09da976 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -40,6 +40,8 @@
type TestOptions struct {
// The UID that you want to run the test as on a device.
Run_test_as *string
+ // A list of free-formed strings without spaces that categorize the test.
+ Test_suite_tag []string
}
type TestBinaryProperties struct {
@@ -357,6 +359,9 @@
if test.Properties.Test_options.Run_test_as != nil {
configs = append(configs, tradefed.Option{Name: "run-test-as", Value: String(test.Properties.Test_options.Run_test_as)})
}
+ for _, tag := range test.Properties.Test_options.Test_suite_tag {
+ configs = append(configs, tradefed.Option{Name: "test-suite-tag", Value: tag})
+ }
if test.Properties.Test_min_api_level != nil && test.Properties.Test_min_sdk_version != nil {
ctx.PropertyErrorf("test_min_api_level", "'test_min_api_level' and 'test_min_sdk_version' should not be set at the same time.")
} else if test.Properties.Test_min_api_level != nil {
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index ea94544..4dad730 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -548,6 +548,10 @@
if !m.IsForPlatform() || m.isSnapshotPrebuilt() || !m.inVendor() {
return false
}
+ // skip kernel_headers which always depend on vendor
+ if _, ok := m.linker.(*kernelHeadersDecorator); ok {
+ return false
+ }
// Libraries
if l, ok := m.linker.(snapshotLibraryInterface); ok {
diff --git a/cc/vndk.go b/cc/vndk.go
index 04b865f..4adf9d2 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -340,16 +340,24 @@
}
}
-func IsForVndkApex(mctx android.BottomUpMutatorContext, m *Module) bool {
+// Sanity check for modules that mustn't be VNDK
+func shouldSkipVndkMutator(m *Module) bool {
if !m.Enabled() {
- return false
+ return true
}
-
- if !mctx.Device() {
- return false
+ if !m.Device() {
+ // Skip non-device modules
+ return true
}
-
if m.Target().NativeBridge == android.NativeBridgeEnabled {
+ // Skip native_bridge modules
+ return true
+ }
+ return false
+}
+
+func IsForVndkApex(mctx android.BottomUpMutatorContext, m *Module) bool {
+ if shouldSkipVndkMutator(m) {
return false
}
@@ -383,11 +391,8 @@
if !ok {
return
}
- if !m.Enabled() {
- return
- }
- if m.Target().NativeBridge == android.NativeBridgeEnabled {
- // Skip native_bridge modules
+
+ if shouldSkipVndkMutator(m) {
return
}
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index d0cad78..c965107 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -171,7 +171,7 @@
buildErrorFile := filepath.Join(logsDir, c.logsPrefix+"build_error")
rbeMetricsFile := filepath.Join(logsDir, c.logsPrefix+"rbe_metrics.pb")
soongMetricsFile := filepath.Join(logsDir, c.logsPrefix+"soong_metrics")
- defer build.UploadMetrics(buildCtx, config, buildStartedMilli, buildErrorFile, rbeMetricsFile, soongMetricsFile)
+ defer build.UploadMetrics(buildCtx, config, c.forceDumbOutput, buildStartedMilli, buildErrorFile, rbeMetricsFile, soongMetricsFile)
os.MkdirAll(logsDir, 0777)
log.SetOutput(filepath.Join(logsDir, c.logsPrefix+"soong.log"))
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 3440f8e..bc44b21 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -123,10 +123,10 @@
ProfileIsTextListing bool
ProfileBootListing android.OptionalPath
- EnforceUsesLibraries bool
- PresentOptionalUsesLibraries []string
- UsesLibraries []string
- LibraryPaths LibraryPaths
+ EnforceUsesLibraries bool
+ OptionalUsesLibraries []string
+ UsesLibraries []string
+ LibraryPaths LibraryPaths
Archs []android.ArchType
DexPreoptImages []android.Path
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 57a9250..9cbe6e5 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -285,7 +285,7 @@
if module.EnforceUsesLibraries {
// Unconditional class loader context.
- usesLibs := append(copyOf(module.UsesLibraries), module.PresentOptionalUsesLibraries...)
+ usesLibs := append(copyOf(module.UsesLibraries), module.OptionalUsesLibraries...)
classLoaderContexts.addLibs(anySdkVersion, module, usesLibs...)
// Conditional class loader context for API version < 28.
diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go
index d239993..ec31549 100644
--- a/dexpreopt/dexpreopt_test.go
+++ b/dexpreopt/dexpreopt_test.go
@@ -44,7 +44,7 @@
ProfileClassListing: android.OptionalPath{},
ProfileIsTextListing: false,
EnforceUsesLibraries: false,
- PresentOptionalUsesLibraries: nil,
+ OptionalUsesLibraries: nil,
UsesLibraries: nil,
LibraryPaths: nil,
Archs: []android.ArchType{android.Arm},
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index d6eb008..df6d79d 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -35,6 +35,7 @@
android.RegisterModuleType("prebuilt_usr_share_host", PrebuiltUserShareHostFactory)
android.RegisterModuleType("prebuilt_font", PrebuiltFontFactory)
android.RegisterModuleType("prebuilt_firmware", PrebuiltFirmwareFactory)
+ android.RegisterModuleType("prebuilt_dsp", PrebuiltDSPFactory)
}
type prebuiltEtcProperties struct {
@@ -293,3 +294,15 @@
android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
return module
}
+
+// prebuilt_dsp installs a DSP related file to <partition>/etc/dsp directory for system image.
+// If soc_specific property is set to true, the DSP related file is installed to the vendor <partition>/dsp
+// directory for vendor image.
+func PrebuiltDSPFactory() android.Module {
+ module := &PrebuiltEtc{}
+ module.socInstallDirBase = "dsp"
+ InitPrebuiltEtcModule(module, "etc/dsp")
+ // This module is device-only
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+ return module
+}
diff --git a/etc/prebuilt_etc_test.go b/etc/prebuilt_etc_test.go
index e13cb3c..4ce1984 100644
--- a/etc/prebuilt_etc_test.go
+++ b/etc/prebuilt_etc_test.go
@@ -65,6 +65,7 @@
ctx.RegisterModuleType("prebuilt_usr_share_host", PrebuiltUserShareHostFactory)
ctx.RegisterModuleType("prebuilt_font", PrebuiltFontFactory)
ctx.RegisterModuleType("prebuilt_firmware", PrebuiltFirmwareFactory)
+ ctx.RegisterModuleType("prebuilt_dsp", PrebuiltDSPFactory)
ctx.Register(config)
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
android.FailIfErrored(t, errs)
@@ -281,3 +282,39 @@
})
}
}
+
+func TestPrebuiltDSPDirPath(t *testing.T) {
+ targetPath := filepath.Join(buildDir, "/target/product/test_device")
+ tests := []struct {
+ description string
+ config string
+ expectedPath string
+ }{{
+ description: "prebuilt: system dsp",
+ config: `
+ prebuilt_dsp {
+ name: "foo.conf",
+ src: "foo.conf",
+ }`,
+ expectedPath: filepath.Join(targetPath, "system/etc/dsp"),
+ }, {
+ description: "prebuilt: vendor dsp",
+ config: `
+ prebuilt_dsp {
+ name: "foo.conf",
+ src: "foo.conf",
+ soc_specific: true,
+ sub_dir: "sub_dir",
+ }`,
+ expectedPath: filepath.Join(targetPath, "vendor/dsp/sub_dir"),
+ }}
+ for _, tt := range tests {
+ t.Run(tt.description, func(t *testing.T) {
+ ctx, _ := testPrebuiltEtc(t, tt.config)
+ p := ctx.ModuleForTests("foo.conf", "android_arm64_armv8-a").Module().(*PrebuiltEtc)
+ if p.installDirPath.String() != tt.expectedPath {
+ t.Errorf("expected %q, got %q", tt.expectedPath, p.installDirPath)
+ }
+ })
+ }
+}
diff --git a/java/Android.bp b/java/Android.bp
index 2de1b8e..1fda7f7 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -37,6 +37,7 @@
"jdeps.go",
"java_resources.go",
"kotlin.go",
+ "lint.go",
"platform_compat_config.go",
"plugin.go",
"prebuilt_apis.go",
diff --git a/java/aar.go b/java/aar.go
index 28e388a..074ead4 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -102,6 +102,7 @@
sdkLibraries []string
hasNoCode bool
LoggingParent string
+ resourceFiles android.Paths
splitNames []string
splits []split
@@ -275,6 +276,7 @@
var compiledResDirs []android.Paths
for _, dir := range resDirs {
+ a.resourceFiles = append(a.resourceFiles, dir.files...)
compiledResDirs = append(compiledResDirs, aapt2Compile(ctx, dir.dir, dir.files, compileFlags).Paths())
}
@@ -473,6 +475,10 @@
// apps manifests are handled by aapt, don't let Module see them
a.properties.Manifest = nil
+ a.linter.mergedManifest = a.aapt.mergedManifestFile
+ a.linter.manifest = a.aapt.manifestPath
+ a.linter.resources = a.aapt.resourceFiles
+
a.Module.extraProguardFlagFiles = append(a.Module.extraProguardFlagFiles,
a.proguardOptionsFile)
@@ -506,15 +512,13 @@
func AndroidLibraryFactory() android.Module {
module := &AndroidLibrary{}
+ module.Module.addHostAndDeviceProperties()
module.AddProperties(
- &module.Module.properties,
- &module.Module.deviceProperties,
- &module.Module.dexpreoptProperties,
- &module.Module.protoProperties,
&module.aaptProperties,
&module.androidLibraryProperties)
module.androidLibraryProperties.BuildAAR = true
+ module.Module.linter.library = true
android.InitApexModule(module)
InitJavaModule(module, android.DeviceSupported)
diff --git a/java/androidmk_test.go b/java/androidmk_test.go
index 7daa624..d471fb7 100644
--- a/java/androidmk_test.go
+++ b/java/androidmk_test.go
@@ -169,3 +169,36 @@
t.Errorf("did not expect explicit DistFile, got %v", without_tag_entries[0].DistFile)
}
}
+
+func TestJavaSdkLibrary_RequireXmlPermissionFile(t *testing.T) {
+ ctx, config := testJava(t, `
+ java_sdk_library {
+ name: "foo-shared_library",
+ srcs: ["a.java"],
+ }
+ java_sdk_library {
+ name: "foo-no_shared_library",
+ srcs: ["a.java"],
+ shared_library: false,
+ }
+ `)
+
+ // Verify the existence of internal modules
+ ctx.ModuleForTests("foo-shared_library.xml", "android_common")
+
+ testCases := []struct {
+ moduleName string
+ expected []string
+ }{
+ {"foo-shared_library", []string{"foo-shared_library.xml"}},
+ {"foo-no_shared_library", nil},
+ }
+ for _, tc := range testCases {
+ mod := ctx.ModuleForTests(tc.moduleName, "android_common").Module()
+ entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0]
+ actual := entries.EntryMap["LOCAL_REQUIRED_MODULES"]
+ if !reflect.DeepEqual(tc.expected, actual) {
+ t.Errorf("Unexpected required modules - expected: %q, actual: %q", tc.expected, actual)
+ }
+ }
+}
diff --git a/java/app.go b/java/app.go
index 0fdede1..c568516 100755
--- a/java/app.go
+++ b/java/app.go
@@ -133,7 +133,7 @@
// We are assuming here that the master file in the APK
// set has `.apk` suffix. If it doesn't the build will fail.
// APK sets containing APEX files are handled elsewhere.
- as.masterFile = ctx.ModuleName() + ".apk"
+ as.masterFile = as.BaseModuleName() + ".apk"
screenDensities := "all"
if dpis := ctx.Config().ProductAAPTPrebuiltDPI(); len(dpis) > 0 {
screenDensities = strings.ToUpper(strings.Join(dpis, ","))
@@ -151,7 +151,7 @@
"allow-prereleased": strconv.FormatBool(proptools.Bool(as.properties.Prerelease)),
"screen-densities": screenDensities,
"sdk-version": ctx.Config().PlatformSdkVersion(),
- "stem": ctx.ModuleName(),
+ "stem": as.BaseModuleName(),
},
})
}
@@ -742,6 +742,10 @@
a.proguardBuildActions(ctx)
+ a.linter.mergedManifest = a.aapt.mergedManifestFile
+ a.linter.manifest = a.aapt.manifestPath
+ a.linter.resources = a.aapt.resourceFiles
+
dexJarFile := a.dexBuildActions(ctx)
jniLibs, certificateDeps := collectAppDeps(ctx, a, a.shouldEmbedJnis(ctx), !Bool(a.appProperties.Jni_uses_platform_apis))
@@ -934,7 +938,7 @@
}
func (a *AndroidApp) IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool {
- return ctx.Device() && (ctx.DeviceConfig().NativeCoverageEnabled() || ctx.DeviceConfig().ClangCoverageEnabled())
+ return ctx.Device() && ctx.DeviceConfig().NativeCoverageEnabled()
}
func (a *AndroidApp) PreventInstall() {
@@ -963,11 +967,8 @@
module.Module.properties.Instrument = true
module.Module.properties.Installable = proptools.BoolPtr(true)
+ module.addHostAndDeviceProperties()
module.AddProperties(
- &module.Module.properties,
- &module.Module.deviceProperties,
- &module.Module.dexpreoptProperties,
- &module.Module.protoProperties,
&module.aaptProperties,
&module.appProperties,
&module.overridableAppProperties,
@@ -1082,12 +1083,10 @@
module.appProperties.Use_embedded_native_libs = proptools.BoolPtr(true)
module.appProperties.AlwaysPackageNativeLibs = true
module.Module.dexpreopter.isTest = true
+ module.Module.linter.test = true
+ module.addHostAndDeviceProperties()
module.AddProperties(
- &module.Module.properties,
- &module.Module.deviceProperties,
- &module.Module.dexpreoptProperties,
- &module.Module.protoProperties,
&module.aaptProperties,
&module.appProperties,
&module.appTestProperties,
@@ -1134,12 +1133,10 @@
module.appProperties.Use_embedded_native_libs = proptools.BoolPtr(true)
module.appProperties.AlwaysPackageNativeLibs = true
module.Module.dexpreopter.isTest = true
+ module.Module.linter.test = true
+ module.addHostAndDeviceProperties()
module.AddProperties(
- &module.Module.properties,
- &module.Module.deviceProperties,
- &module.Module.dexpreoptProperties,
- &module.Module.protoProperties,
&module.aaptProperties,
&module.appProperties,
&module.appTestHelperAppProperties,
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index c33415e..7f1afd6 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -193,10 +193,10 @@
ProfileIsTextListing: profileIsTextListing,
ProfileBootListing: profileBootListing,
- EnforceUsesLibraries: d.enforceUsesLibs,
- PresentOptionalUsesLibraries: d.optionalUsesLibs,
- UsesLibraries: d.usesLibs,
- LibraryPaths: d.libraryPaths,
+ EnforceUsesLibraries: d.enforceUsesLibs,
+ OptionalUsesLibraries: d.optionalUsesLibs,
+ UsesLibraries: d.usesLibs,
+ LibraryPaths: d.libraryPaths,
Archs: archs,
DexPreoptImages: images,
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 68cfe9f..a0b7edf 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -121,6 +121,10 @@
// names of the output files used in args that will be generated
Out []string
+
+ // If set, metalava is sandboxed to only read files explicitly specified on the command
+ // line. Defaults to false.
+ Sandbox *bool
}
type ApiToCheck struct {
@@ -1224,6 +1228,21 @@
return module
}
+func (d *Droidstubs) OutputFiles(tag string) (android.Paths, error) {
+ switch tag {
+ case "":
+ return android.Paths{d.stubsSrcJar}, nil
+ case ".docs.zip":
+ return android.Paths{d.docZip}, nil
+ case ".annotations.zip":
+ return android.Paths{d.annotationsZip}, nil
+ case ".api_versions.xml":
+ return android.Paths{d.apiVersionsXml}, nil
+ default:
+ return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+ }
+}
+
func (d *Droidstubs) ApiFilePath() android.Path {
return d.apiFilePath
}
@@ -1306,6 +1325,7 @@
cmd.Flag("--exclude-documentation-from-stubs")
}
}
+ cmd.FlagWithArg("--hide ", "ShowingMemberInHiddenClass") // b/159121253 -- remove it once all the violations are fixed.
}
func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
@@ -1399,7 +1419,7 @@
}
func (d *Droidstubs) apiToXmlFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
- if Bool(d.properties.Jdiff_enabled) && !ctx.Config().IsPdkBuild() {
+ if Bool(d.properties.Jdiff_enabled) && !ctx.Config().IsPdkBuild() && d.apiFile != nil {
if d.apiFile.String() == "" {
ctx.ModuleErrorf("API signature file has to be specified in Metalava when jdiff is enabled.")
}
@@ -1419,41 +1439,25 @@
}
func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion javaVersion, srcs android.Paths,
- srcJarList android.Path, bootclasspath, classpath classpath, sourcepaths android.Paths, implicits android.Paths) *android.RuleBuilderCommand {
+ srcJarList android.Path, bootclasspath, classpath classpath, sourcepaths android.Paths, implicitsRsp android.WritablePath, sandbox bool) *android.RuleBuilderCommand {
// Metalava uses lots of memory, restrict the number of metalava jobs that can run in parallel.
rule.HighMem()
cmd := rule.Command()
-
- var implicitsRsp android.WritablePath
- if len(implicits) > 0 {
- implicitsRsp = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"implicits.rsp")
- impRule := android.NewRuleBuilder()
- impCmd := impRule.Command()
- // A dummy action that copies the ninja generated rsp file to a new location. This allows us to
- // add a large number of inputs to a file without exceeding bash command length limits (which
- // would happen if we use the WriteFile rule). The cp is needed because RuleBuilder sets the
- // rsp file to be ${output}.rsp.
- impCmd.Text("cp").FlagWithRspFileInputList("", implicits).Output(implicitsRsp)
- impRule.Build(pctx, ctx, "implicitsGen", "implicits generation")
- cmd.Implicits(implicits)
- cmd.Implicit(implicitsRsp)
- }
if ctx.Config().IsEnvTrue("RBE_METALAVA") {
rule.Remoteable(android.RemoteRuleSupports{RBE: true})
- execStrategy := remoteexec.LocalExecStrategy
- if v := ctx.Config().Getenv("RBE_METALAVA_EXEC_STRATEGY"); v != "" {
- execStrategy = v
- }
- pool := "metalava"
- if v := ctx.Config().Getenv("RBE_METALAVA_POOL"); v != "" {
- pool = v
+ pool := ctx.Config().GetenvWithDefault("RBE_METALAVA_POOL", "metalava")
+ execStrategy := ctx.Config().GetenvWithDefault("RBE_METALAVA_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
+ labels := map[string]string{"type": "compile", "lang": "java", "compiler": "metalava"}
+ if !sandbox {
+ execStrategy = remoteexec.LocalExecStrategy
+ labels["shallow"] = "true"
}
inputs := []string{android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "metalava.jar").String()}
if v := ctx.Config().Getenv("RBE_METALAVA_INPUTS"); v != "" {
inputs = append(inputs, strings.Split(v, ",")...)
}
cmd.Text((&remoteexec.REParams{
- Labels: map[string]string{"type": "compile", "lang": "java", "compiler": "metalava", "shallow": "true"},
+ Labels: labels,
ExecStrategy: execStrategy,
Inputs: inputs,
RSPFile: implicitsRsp.String(),
@@ -1467,8 +1471,17 @@
FlagWithArg("-encoding ", "UTF-8").
FlagWithArg("-source ", javaVersion.String()).
FlagWithRspFileInputList("@", srcs).
- FlagWithInput("@", srcJarList).
- FlagWithOutput("--strict-input-files:warn ", android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"violations.txt"))
+ FlagWithInput("@", srcJarList)
+
+ if javaHome := ctx.Config().Getenv("ANDROID_JAVA_HOME"); javaHome != "" {
+ cmd.Implicit(android.PathForSource(ctx, javaHome))
+ }
+
+ if sandbox {
+ cmd.FlagWithOutput("--strict-input-files ", android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"violations.txt"))
+ } else {
+ cmd.FlagWithOutput("--strict-input-files:warn ", android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"violations.txt"))
+ }
if implicitsRsp != nil {
cmd.FlagWithArg("--strict-input-files-exempt ", "@"+implicitsRsp.String())
@@ -1518,8 +1531,12 @@
srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
+ implicitsRsp := android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"implicits.rsp")
+
cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList,
- deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths, d.Javadoc.implicits)
+ deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths, implicitsRsp,
+ Bool(d.Javadoc.properties.Sandbox))
+ cmd.Implicits(d.Javadoc.implicits)
d.stubsFlags(ctx, cmd, stubsDir)
@@ -1638,6 +1655,16 @@
cmd.FlagWithArg("--error-message:compatibility:released ", msg)
}
+ impRule := android.NewRuleBuilder()
+ impCmd := impRule.Command()
+ // A dummy action that copies the ninja generated rsp file to a new location. This allows us to
+ // add a large number of inputs to a file without exceeding bash command length limits (which
+ // would happen if we use the WriteFile rule). The cp is needed because RuleBuilder sets the
+ // rsp file to be ${output}.rsp.
+ impCmd.Text("cp").FlagWithRspFileInputList("", cmd.GetImplicits()).Output(implicitsRsp)
+ impRule.Build(pctx, ctx, "implicitsGen", "implicits generation")
+ cmd.Implicit(implicitsRsp)
+
if generateStubs {
rule.Command().
BuiltTool(ctx, "soong_zip").
@@ -1820,13 +1847,19 @@
Flag("-XDignore.symbol.file").
FlagWithArg("-doclet ", "jdiff.JDiff").
FlagWithInput("-docletpath ", jdiff).
- Flag("-quiet").
- FlagWithArg("-newapi ", strings.TrimSuffix(d.apiXmlFile.Base(), d.apiXmlFile.Ext())).
- FlagWithArg("-newapidir ", filepath.Dir(d.apiXmlFile.String())).
- Implicit(d.apiXmlFile).
- FlagWithArg("-oldapi ", strings.TrimSuffix(d.lastReleasedApiXmlFile.Base(), d.lastReleasedApiXmlFile.Ext())).
- FlagWithArg("-oldapidir ", filepath.Dir(d.lastReleasedApiXmlFile.String())).
- Implicit(d.lastReleasedApiXmlFile)
+ Flag("-quiet")
+
+ if d.apiXmlFile != nil {
+ cmd.FlagWithArg("-newapi ", strings.TrimSuffix(d.apiXmlFile.Base(), d.apiXmlFile.Ext())).
+ FlagWithArg("-newapidir ", filepath.Dir(d.apiXmlFile.String())).
+ Implicit(d.apiXmlFile)
+ }
+
+ if d.lastReleasedApiXmlFile != nil {
+ cmd.FlagWithArg("-oldapi ", strings.TrimSuffix(d.lastReleasedApiXmlFile.Base(), d.lastReleasedApiXmlFile.Ext())).
+ FlagWithArg("-oldapidir ", filepath.Dir(d.lastReleasedApiXmlFile.String())).
+ Implicit(d.lastReleasedApiXmlFile)
+ }
rule.Command().
BuiltTool(ctx, "soong_zip").
diff --git a/java/java.go b/java/java.go
index 1cdfbf1..7a42557 100644
--- a/java/java.go
+++ b/java/java.go
@@ -253,6 +253,9 @@
// List of files to include in the META-INF/services folder of the resulting jar.
Services []string `android:"path,arch_variant"`
+
+ // If true, package the kotlin stdlib into the jar. Defaults to true.
+ Static_kotlin_stdlib *bool `android:"arch_variant"`
}
type CompilerDeviceProperties struct {
@@ -471,6 +474,7 @@
hiddenAPI
dexpreopter
+ linter
// list of the xref extraction files
kytheFiles android.Paths
@@ -481,6 +485,22 @@
modulePaths []string
}
+func (j *Module) addHostProperties() {
+ j.AddProperties(
+ &j.properties,
+ &j.protoProperties,
+ )
+}
+
+func (j *Module) addHostAndDeviceProperties() {
+ j.addHostProperties()
+ j.AddProperties(
+ &j.deviceProperties,
+ &j.dexpreoptProperties,
+ &j.linter.properties,
+ )
+}
+
func (j *Module) OutputFiles(tag string) (android.Paths, error) {
switch tag {
case "":
@@ -496,11 +516,16 @@
var _ android.OutputFileProducer = (*Module)(nil)
-type Dependency interface {
+// Methods that need to be implemented for a module that is added to apex java_libs property.
+type ApexDependency interface {
HeaderJars() android.Paths
+ ImplementationAndResourcesJars() android.Paths
+}
+
+type Dependency interface {
+ ApexDependency
ImplementationJars() android.Paths
ResourceJars() android.Paths
- ImplementationAndResourcesJars() android.Paths
DexJarBuildPath() android.Path
DexJarInstallPath() android.Path
AidlIncludeDirs() android.Paths
@@ -554,6 +579,7 @@
certificateTag = dependencyTag{name: "certificate"}
instrumentationForTag = dependencyTag{name: "instrumentation_for"}
usesLibTag = dependencyTag{name: "uses-library"}
+ extraLintCheckTag = dependencyTag{name: "extra-lint-check"}
)
func IsLibDepTag(depTag blueprint.DependencyTag) bool {
@@ -601,7 +627,9 @@
}
func (j *Module) shouldInstrument(ctx android.BaseModuleContext) bool {
- return j.properties.Instrument && ctx.Config().IsEnvTrue("EMMA_INSTRUMENT")
+ return j.properties.Instrument &&
+ ctx.Config().IsEnvTrue("EMMA_INSTRUMENT") &&
+ ctx.DeviceConfig().JavaCoverageEnabledForPath(ctx.ModuleDir())
}
func (j *Module) shouldInstrumentStatic(ctx android.BaseModuleContext) bool {
@@ -610,6 +638,21 @@
ctx.Config().UnbundledBuild())
}
+func (j *Module) shouldInstrumentInApex(ctx android.BaseModuleContext) bool {
+ // Force enable the instrumentation for java code that is built for APEXes ...
+ // except for the jacocoagent itself (because instrumenting jacocoagent using jacocoagent
+ // doesn't make sense) or framework libraries (e.g. libraries found in the InstrumentFrameworkModules list) unless EMMA_INSTRUMENT_FRAMEWORK is true.
+ isJacocoAgent := ctx.ModuleName() == "jacocoagent"
+ if android.DirectlyInAnyApex(ctx, ctx.ModuleName()) && !isJacocoAgent && !j.IsForPlatform() {
+ if !inList(ctx.ModuleName(), config.InstrumentFrameworkModules) {
+ return true
+ } else if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
+ return true
+ }
+ }
+ return false
+}
+
func (j *Module) sdkVersion() sdkSpec {
return sdkSpecFrom(String(j.deviceProperties.Sdk_version))
}
@@ -648,6 +691,8 @@
func (j *Module) deps(ctx android.BottomUpMutatorContext) {
if ctx.Device() {
+ j.linter.deps(ctx)
+
sdkDep := decodeSdkDep(ctx, sdkContext(j))
if sdkDep.useDefaultLibs {
ctx.AddVariationDependencies(nil, bootClasspathTag, config.DefaultBootclasspathLibraries...)
@@ -1150,9 +1195,9 @@
if flags.javaVersion.usesJavaModules() {
javacFlags = append(javacFlags, j.properties.Openjdk9.Javacflags...)
}
- if ctx.Config().MinimizeJavaDebugInfo() {
- // Override the -g flag passed globally to remove local variable debug info to reduce
- // disk and memory usage.
+ if ctx.Config().MinimizeJavaDebugInfo() && !ctx.Host() {
+ // For non-host binaries, override the -g flag passed globally to remove
+ // local variable debug info to reduce disk and memory usage.
javacFlags = append(javacFlags, "-g:source,lines")
}
javacFlags = append(javacFlags, "-Xlint:-dep-ann")
@@ -1311,8 +1356,10 @@
if len(flags.processorPath) > 0 {
// Use kapt for annotation processing
kaptSrcJar := android.PathForModuleOut(ctx, "kapt", "kapt-sources.jar")
- kotlinKapt(ctx, kaptSrcJar, kotlinSrcFiles, srcJars, flags)
+ kaptResJar := android.PathForModuleOut(ctx, "kapt", "kapt-res.jar")
+ kotlinKapt(ctx, kaptSrcJar, kaptResJar, kotlinSrcFiles, srcJars, flags)
srcJars = append(srcJars, kaptSrcJar)
+ kotlinJars = append(kotlinJars, kaptResJar)
// Disable annotation processing in javac, it's already been handled by kapt
flags.processorPath = nil
flags.processors = nil
@@ -1327,9 +1374,11 @@
// Make javac rule depend on the kotlinc rule
flags.classpath = append(flags.classpath, kotlinJar)
- // Jar kotlin classes into the final jar after javac
kotlinJars = append(kotlinJars, kotlinJar)
- kotlinJars = append(kotlinJars, deps.kotlinStdlib...)
+ // Jar kotlin classes into the final jar after javac
+ if BoolDefault(j.properties.Static_kotlin_stdlib, true) {
+ kotlinJars = append(kotlinJars, deps.kotlinStdlib...)
+ }
}
jars := append(android.Paths(nil), kotlinJars...)
@@ -1543,11 +1592,7 @@
j.headerJarFile = j.implementationJarFile
}
- // Force enable the instrumentation for java code that is built for APEXes ...
- // except for the jacocoagent itself (because instrumenting jacocoagent using jacocoagent
- // doesn't make sense)
- isJacocoAgent := ctx.ModuleName() == "jacocoagent"
- if android.DirectlyInAnyApex(ctx, ctx.ModuleName()) && !isJacocoAgent && !j.IsForPlatform() {
+ if j.shouldInstrumentInApex(ctx) {
j.properties.Instrument = true
}
@@ -1621,6 +1666,28 @@
outputFile = implementationAndResourcesJar
}
+ if ctx.Device() {
+ lintSDKVersionString := func(sdkSpec sdkSpec) string {
+ if v := sdkSpec.version; v.isNumbered() {
+ return v.String()
+ } else {
+ return ctx.Config().DefaultAppTargetSdk()
+ }
+ }
+
+ j.linter.name = ctx.ModuleName()
+ j.linter.srcs = srcFiles
+ j.linter.srcJars = srcJars
+ j.linter.classpath = append(append(android.Paths(nil), flags.bootClasspath...), flags.classpath...)
+ j.linter.classes = j.implementationJarFile
+ j.linter.minSdkVersion = lintSDKVersionString(j.minSdkVersion())
+ j.linter.targetSdkVersion = lintSDKVersionString(j.targetSdkVersion())
+ j.linter.compileSdkVersion = lintSDKVersionString(j.sdkVersion())
+ j.linter.javaLanguageLevel = flags.javaVersion.String()
+ j.linter.kotlinLanguageLevel = "1.3"
+ j.linter.lint(ctx)
+ }
+
ctx.CheckbuildFile(outputFile)
// Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource
@@ -2033,12 +2100,8 @@
func LibraryFactory() android.Module {
module := &Library{}
- module.AddProperties(
- &module.Module.properties,
- &module.Module.deviceProperties,
- &module.Module.dexpreoptProperties,
- &module.Module.protoProperties,
- &module.libraryProperties)
+ module.addHostAndDeviceProperties()
+ module.AddProperties(&module.libraryProperties)
module.initModuleAndImport(&module.ModuleBase)
@@ -2060,9 +2123,7 @@
func LibraryHostFactory() android.Module {
module := &Library{}
- module.AddProperties(
- &module.Module.properties,
- &module.Module.protoProperties)
+ module.addHostProperties()
module.Module.properties.Installable = proptools.BoolPtr(true)
@@ -2230,15 +2291,12 @@
func TestFactory() android.Module {
module := &Test{}
- module.AddProperties(
- &module.Module.properties,
- &module.Module.deviceProperties,
- &module.Module.dexpreoptProperties,
- &module.Module.protoProperties,
- &module.testProperties)
+ module.addHostAndDeviceProperties()
+ module.AddProperties(&module.testProperties)
module.Module.properties.Installable = proptools.BoolPtr(true)
module.Module.dexpreopter.isTest = true
+ module.Module.linter.test = true
InitJavaModule(module, android.HostAndDeviceSupported)
return module
@@ -2248,15 +2306,12 @@
func TestHelperLibraryFactory() android.Module {
module := &TestHelperLibrary{}
- module.AddProperties(
- &module.Module.properties,
- &module.Module.deviceProperties,
- &module.Module.dexpreoptProperties,
- &module.Module.protoProperties,
- &module.testHelperLibraryProperties)
+ module.addHostAndDeviceProperties()
+ module.AddProperties(&module.testHelperLibraryProperties)
module.Module.properties.Installable = proptools.BoolPtr(true)
module.Module.dexpreopter.isTest = true
+ module.Module.linter.test = true
InitJavaModule(module, android.HostAndDeviceSupported)
return module
@@ -2294,10 +2349,8 @@
func TestHostFactory() android.Module {
module := &Test{}
- module.AddProperties(
- &module.Module.properties,
- &module.Module.protoProperties,
- &module.testProperties)
+ module.addHostProperties()
+ module.AddProperties(&module.testProperties)
module.Module.properties.Installable = proptools.BoolPtr(true)
@@ -2381,12 +2434,8 @@
func BinaryFactory() android.Module {
module := &Binary{}
- module.AddProperties(
- &module.Module.properties,
- &module.Module.deviceProperties,
- &module.Module.dexpreoptProperties,
- &module.Module.protoProperties,
- &module.binaryProperties)
+ module.addHostAndDeviceProperties()
+ module.AddProperties(&module.binaryProperties)
module.Module.properties.Installable = proptools.BoolPtr(true)
@@ -2402,10 +2451,8 @@
func BinaryHostFactory() android.Module {
module := &Binary{}
- module.AddProperties(
- &module.Module.properties,
- &module.Module.protoProperties,
- &module.binaryProperties)
+ module.addHostProperties()
+ module.AddProperties(&module.binaryProperties)
module.Module.properties.Installable = proptools.BoolPtr(true)
@@ -2852,6 +2899,7 @@
&DexImportProperties{},
&android.ApexProperties{},
&RuntimeResourceOverlayProperties{},
+ &LintProperties{},
)
android.InitDefaultsModule(module)
diff --git a/java/java_test.go b/java/java_test.go
index 215070e..1d07e70 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -466,7 +466,41 @@
t.Errorf("expected binary wrapper implicits [%q], got %v",
barJar, barWrapperDeps)
}
+}
+func TestHostBinaryNoJavaDebugInfoOverride(t *testing.T) {
+ bp := `
+ java_library {
+ name: "target_library",
+ srcs: ["a.java"],
+ }
+
+ java_binary_host {
+ name: "host_binary",
+ srcs: ["b.java"],
+ }
+ `
+ config := testConfig(nil, bp, nil)
+ config.TestProductVariables.MinimizeJavaDebugInfo = proptools.BoolPtr(true)
+
+ ctx, _ := testJavaWithConfig(t, config)
+
+ // first, sanity check that the -g flag is added to target modules
+ targetLibrary := ctx.ModuleForTests("target_library", "android_common")
+ targetJavaFlags := targetLibrary.Module().VariablesForTests()["javacFlags"]
+ if !strings.Contains(targetJavaFlags, "-g:source,lines") {
+ t.Errorf("target library javac flags %v should contain "+
+ "-g:source,lines override with MinimizeJavaDebugInfo", targetJavaFlags)
+ }
+
+ // check that -g is not overridden for host modules
+ buildOS := android.BuildOs.String()
+ hostBinary := ctx.ModuleForTests("host_binary", buildOS+"_common")
+ hostJavaFlags := hostBinary.Module().VariablesForTests()["javacFlags"]
+ if strings.Contains(hostJavaFlags, "-g:source,lines") {
+ t.Errorf("java_binary_host javac flags %v should not have "+
+ "-g:source,lines override with MinimizeJavaDebugInfo", hostJavaFlags)
+ }
}
func TestPrebuilts(t *testing.T) {
@@ -1448,6 +1482,38 @@
`)
}
+func TestJavaSdkLibrary_ModuleLib(t *testing.T) {
+ testJava(t, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java", "b.java"],
+ api_packages: ["foo"],
+ system: {
+ enabled: true,
+ },
+ module_lib: {
+ enabled: true,
+ },
+ }
+ `)
+}
+
+func TestJavaSdkLibrary_SystemServer(t *testing.T) {
+ testJava(t, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java", "b.java"],
+ api_packages: ["foo"],
+ system: {
+ enabled: true,
+ },
+ system_server: {
+ enabled: true,
+ },
+ }
+ `)
+}
+
func TestJavaSdkLibrary_MissingScope(t *testing.T) {
testJavaError(t, `requires api scope module-lib from foo but it only has \[\] available`, `
java_sdk_library {
diff --git a/java/kotlin.go b/java/kotlin.go
index 9b160a0..673970b 100644
--- a/java/kotlin.go
+++ b/java/kotlin.go
@@ -90,7 +90,8 @@
var kapt = pctx.AndroidRemoteStaticRule("kapt", android.RemoteRuleSupports{Goma: true},
blueprint.RuleParams{
- Command: `rm -rf "$srcJarDir" "$kotlinBuildFile" "$kaptDir" && mkdir -p "$srcJarDir" "$kaptDir" && ` +
+ Command: `rm -rf "$srcJarDir" "$kotlinBuildFile" "$kaptDir" && ` +
+ `mkdir -p "$srcJarDir" "$kaptDir/sources" "$kaptDir/classes" && ` +
`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
`${config.GenKotlinBuildFileCmd} $classpath "$name" "" $out.rsp $srcJarDir/list > $kotlinBuildFile &&` +
`${config.KotlincCmd} ${config.KotlincSuppressJDK9Warnings} ${config.JavacHeapFlags} $kotlincFlags ` +
@@ -105,6 +106,7 @@
`$kaptProcessor ` +
`-Xbuild-file=$kotlinBuildFile && ` +
`${config.SoongZipCmd} -jar -o $out -C $kaptDir/sources -D $kaptDir/sources && ` +
+ `${config.SoongZipCmd} -jar -o $classesJarOut -C $kaptDir/classes -D $kaptDir/classes && ` +
`rm -rf "$srcJarDir"`,
CommandDeps: []string{
"${config.KotlincCmd}",
@@ -118,13 +120,14 @@
RspfileContent: `$in`,
},
"kotlincFlags", "encodedJavacFlags", "kaptProcessorPath", "kaptProcessor",
- "classpath", "srcJars", "srcJarDir", "kaptDir", "kotlinJvmTarget", "kotlinBuildFile", "name")
+ "classpath", "srcJars", "srcJarDir", "kaptDir", "kotlinJvmTarget", "kotlinBuildFile", "name",
+ "classesJarOut")
// kotlinKapt performs Kotlin-compatible annotation processing. It takes .kt and .java sources and srcjars, and runs
// annotation processors over all of them, producing a srcjar of generated code in outputFile. The srcjar should be
// added as an additional input to kotlinc and javac rules, and the javac rule should have annotation processing
// disabled.
-func kotlinKapt(ctx android.ModuleContext, outputFile android.WritablePath,
+func kotlinKapt(ctx android.ModuleContext, srcJarOutputFile, resJarOutputFile android.WritablePath,
srcFiles, srcJars android.Paths,
flags javaBuilderFlags) {
@@ -152,11 +155,12 @@
kotlinName = strings.ReplaceAll(kotlinName, "/", "__")
ctx.Build(pctx, android.BuildParams{
- Rule: kapt,
- Description: "kapt",
- Output: outputFile,
- Inputs: srcFiles,
- Implicits: deps,
+ Rule: kapt,
+ Description: "kapt",
+ Output: srcJarOutputFile,
+ ImplicitOutput: resJarOutputFile,
+ Inputs: srcFiles,
+ Implicits: deps,
Args: map[string]string{
"classpath": flags.kotlincClasspath.FormJavaClassPath("-classpath"),
"kotlincFlags": flags.kotlincFlags,
@@ -168,6 +172,7 @@
"kaptDir": android.PathForModuleOut(ctx, "kapt/gen").String(),
"encodedJavacFlags": encodedJavacFlags,
"name": kotlinName,
+ "classesJarOut": resJarOutputFile.String(),
},
})
}
diff --git a/java/lint.go b/java/lint.go
new file mode 100644
index 0000000..b73d6a5
--- /dev/null
+++ b/java/lint.go
@@ -0,0 +1,381 @@
+// Copyright 2020 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 java
+
+import (
+ "fmt"
+ "sort"
+
+ "android/soong/android"
+)
+
+type LintProperties struct {
+ // Controls for running Android Lint on the module.
+ Lint struct {
+
+ // If true, run Android Lint on the module. Defaults to true.
+ Enabled *bool
+
+ // Flags to pass to the Android Lint tool.
+ Flags []string
+
+ // Checks that should be treated as fatal.
+ Fatal_checks []string
+
+ // Checks that should be treated as errors.
+ Error_checks []string
+
+ // Checks that should be treated as warnings.
+ Warning_checks []string
+
+ // Checks that should be skipped.
+ Disabled_checks []string
+
+ // Modules that provide extra lint checks
+ Extra_check_modules []string
+ }
+}
+
+type linter struct {
+ name string
+ manifest android.Path
+ mergedManifest android.Path
+ srcs android.Paths
+ srcJars android.Paths
+ resources android.Paths
+ classpath android.Paths
+ classes android.Path
+ extraLintCheckJars android.Paths
+ test bool
+ library bool
+ minSdkVersion string
+ targetSdkVersion string
+ compileSdkVersion string
+ javaLanguageLevel string
+ kotlinLanguageLevel string
+ outputs lintOutputs
+ properties LintProperties
+}
+
+type lintOutputs struct {
+ html android.ModuleOutPath
+ text android.ModuleOutPath
+ xml android.ModuleOutPath
+}
+
+func (l *linter) enabled() bool {
+ return BoolDefault(l.properties.Lint.Enabled, true)
+}
+
+func (l *linter) deps(ctx android.BottomUpMutatorContext) {
+ if !l.enabled() {
+ return
+ }
+
+ ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), extraLintCheckTag, l.properties.Lint.Extra_check_modules...)
+}
+
+func (l *linter) writeLintProjectXML(ctx android.ModuleContext,
+ rule *android.RuleBuilder) (projectXMLPath, configXMLPath, cacheDir, homeDir android.WritablePath, deps android.Paths) {
+
+ var resourcesList android.WritablePath
+ if len(l.resources) > 0 {
+ // The list of resources may be too long to put on the command line, but
+ // we can't use the rsp file because it is already being used for srcs.
+ // Insert a second rule to write out the list of resources to a file.
+ resourcesList = android.PathForModuleOut(ctx, "lint", "resources.list")
+ resListRule := android.NewRuleBuilder()
+ resListRule.Command().Text("cp").FlagWithRspFileInputList("", l.resources).Output(resourcesList)
+ resListRule.Build(pctx, ctx, "lint_resources_list", "lint resources list")
+ deps = append(deps, l.resources...)
+ }
+
+ projectXMLPath = android.PathForModuleOut(ctx, "lint", "project.xml")
+ // Lint looks for a lint.xml file next to the project.xml file, give it one.
+ configXMLPath = android.PathForModuleOut(ctx, "lint", "lint.xml")
+ cacheDir = android.PathForModuleOut(ctx, "lint", "cache")
+ homeDir = android.PathForModuleOut(ctx, "lint", "home")
+
+ srcJarDir := android.PathForModuleOut(ctx, "lint-srcjars")
+ srcJarList := zipSyncCmd(ctx, rule, srcJarDir, l.srcJars)
+
+ cmd := rule.Command().
+ BuiltTool(ctx, "lint-project-xml").
+ FlagWithOutput("--project_out ", projectXMLPath).
+ FlagWithOutput("--config_out ", configXMLPath).
+ FlagWithArg("--name ", ctx.ModuleName())
+
+ if l.library {
+ cmd.Flag("--library")
+ }
+ if l.test {
+ cmd.Flag("--test")
+ }
+ if l.manifest != nil {
+ deps = append(deps, l.manifest)
+ cmd.FlagWithArg("--manifest ", l.manifest.String())
+ }
+ if l.mergedManifest != nil {
+ deps = append(deps, l.mergedManifest)
+ cmd.FlagWithArg("--merged_manifest ", l.mergedManifest.String())
+ }
+
+ // TODO(ccross): some of the files in l.srcs are generated sources and should be passed to
+ // lint separately.
+ cmd.FlagWithRspFileInputList("--srcs ", l.srcs)
+ deps = append(deps, l.srcs...)
+
+ cmd.FlagWithInput("--generated_srcs ", srcJarList)
+ deps = append(deps, l.srcJars...)
+
+ if resourcesList != nil {
+ cmd.FlagWithInput("--resources ", resourcesList)
+ }
+
+ if l.classes != nil {
+ deps = append(deps, l.classes)
+ cmd.FlagWithArg("--classes ", l.classes.String())
+ }
+
+ cmd.FlagForEachArg("--classpath ", l.classpath.Strings())
+ deps = append(deps, l.classpath...)
+
+ cmd.FlagForEachArg("--extra_checks_jar ", l.extraLintCheckJars.Strings())
+ deps = append(deps, l.extraLintCheckJars...)
+
+ cmd.FlagWithArg("--root_dir ", "$PWD")
+
+ // The cache tag in project.xml is relative to the root dir, or the project.xml file if
+ // the root dir is not set.
+ cmd.FlagWithArg("--cache_dir ", cacheDir.String())
+
+ cmd.FlagWithInput("@",
+ android.PathForSource(ctx, "build/soong/java/lint_defaults.txt"))
+
+ cmd.FlagForEachArg("--disable_check ", l.properties.Lint.Disabled_checks)
+ cmd.FlagForEachArg("--warning_check ", l.properties.Lint.Warning_checks)
+ cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
+ cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
+
+ return projectXMLPath, configXMLPath, cacheDir, homeDir, deps
+}
+
+// generateManifest adds a command to the rule to write a dummy manifest cat contains the
+// minSdkVersion and targetSdkVersion for modules (like java_library) that don't have a manifest.
+func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleBuilder) android.Path {
+ manifestPath := android.PathForModuleOut(ctx, "lint", "AndroidManifest.xml")
+
+ rule.Command().Text("(").
+ Text(`echo "<?xml version='1.0' encoding='utf-8'?>" &&`).
+ Text(`echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" &&`).
+ Text(`echo " android:versionCode='1' android:versionName='1' >" &&`).
+ Textf(`echo " <uses-sdk android:minSdkVersion='%s' android:targetSdkVersion='%s'/>" &&`,
+ l.minSdkVersion, l.targetSdkVersion).
+ Text(`echo "</manifest>"`).
+ Text(") >").Output(manifestPath)
+
+ return manifestPath
+}
+
+func (l *linter) lint(ctx android.ModuleContext) {
+ if !l.enabled() {
+ return
+ }
+
+ extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag)
+ for _, extraLintCheckModule := range extraLintCheckModules {
+ if dep, ok := extraLintCheckModule.(Dependency); ok {
+ l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars()...)
+ } else {
+ ctx.PropertyErrorf("lint.extra_check_modules",
+ "%s is not a java module", ctx.OtherModuleName(extraLintCheckModule))
+ }
+ }
+
+ rule := android.NewRuleBuilder()
+
+ if l.manifest == nil {
+ manifest := l.generateManifest(ctx, rule)
+ l.manifest = manifest
+ }
+
+ projectXML, lintXML, cacheDir, homeDir, deps := l.writeLintProjectXML(ctx, rule)
+
+ l.outputs.html = android.PathForModuleOut(ctx, "lint-report.html")
+ l.outputs.text = android.PathForModuleOut(ctx, "lint-report.txt")
+ l.outputs.xml = android.PathForModuleOut(ctx, "lint-report.xml")
+
+ rule.Command().Text("rm -rf").Flag(cacheDir.String()).Flag(homeDir.String())
+ rule.Command().Text("mkdir -p").Flag(cacheDir.String()).Flag(homeDir.String())
+
+ rule.Command().
+ Text("(").
+ Flag("JAVA_OPTS=-Xmx2048m").
+ FlagWithArg("ANDROID_SDK_HOME=", homeDir.String()).
+ FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath(ctx)).
+ FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXmlPath(ctx)).
+ Tool(android.PathForSource(ctx, "prebuilts/cmdline-tools/tools/bin/lint")).
+ Implicit(android.PathForSource(ctx, "prebuilts/cmdline-tools/tools/lib/lint-classpath.jar")).
+ Flag("--quiet").
+ FlagWithInput("--project ", projectXML).
+ FlagWithInput("--config ", lintXML).
+ FlagWithOutput("--html ", l.outputs.html).
+ FlagWithOutput("--text ", l.outputs.text).
+ FlagWithOutput("--xml ", l.outputs.xml).
+ FlagWithArg("--compile-sdk-version ", l.compileSdkVersion).
+ FlagWithArg("--java-language-level ", l.javaLanguageLevel).
+ FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
+ FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
+ Flag("--exitcode").
+ Flags(l.properties.Lint.Flags).
+ Implicits(deps).
+ Text("|| (").Text("cat").Input(l.outputs.text).Text("; exit 7)").
+ Text(")")
+
+ rule.Command().Text("rm -rf").Flag(cacheDir.String()).Flag(homeDir.String())
+
+ rule.Build(pctx, ctx, "lint", "lint")
+}
+
+func (l *linter) lintOutputs() *lintOutputs {
+ return &l.outputs
+}
+
+type lintOutputIntf interface {
+ lintOutputs() *lintOutputs
+}
+
+var _ lintOutputIntf = (*linter)(nil)
+
+type lintSingleton struct {
+ htmlZip android.WritablePath
+ textZip android.WritablePath
+ xmlZip android.WritablePath
+}
+
+func (l *lintSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+ l.generateLintReportZips(ctx)
+ l.copyLintDependencies(ctx)
+}
+
+func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) {
+ if ctx.Config().UnbundledBuild() {
+ return
+ }
+
+ var frameworkDocStubs android.Module
+ ctx.VisitAllModules(func(m android.Module) {
+ if ctx.ModuleName(m) == "framework-doc-stubs" {
+ if frameworkDocStubs == nil {
+ frameworkDocStubs = m
+ } else {
+ ctx.Errorf("lint: multiple framework-doc-stubs modules found: %s and %s",
+ ctx.ModuleSubDir(m), ctx.ModuleSubDir(frameworkDocStubs))
+ }
+ }
+ })
+
+ if frameworkDocStubs == nil {
+ if !ctx.Config().AllowMissingDependencies() {
+ ctx.Errorf("lint: missing framework-doc-stubs")
+ }
+ return
+ }
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".annotations.zip"),
+ Output: annotationsZipPath(ctx),
+ })
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".api_versions.xml"),
+ Output: apiVersionsXmlPath(ctx),
+ })
+}
+
+func annotationsZipPath(ctx android.PathContext) android.WritablePath {
+ return android.PathForOutput(ctx, "lint", "annotations.zip")
+}
+
+func apiVersionsXmlPath(ctx android.PathContext) android.WritablePath {
+ return android.PathForOutput(ctx, "lint", "api_versions.xml")
+}
+
+func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) {
+ var outputs []*lintOutputs
+ var dirs []string
+ ctx.VisitAllModules(func(m android.Module) {
+ if ctx.Config().EmbeddedInMake() && !m.ExportedToMake() {
+ return
+ }
+
+ if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() && apex.IsForPlatform() {
+ // There are stray platform variants of modules in apexes that are not available for
+ // the platform, and they sometimes can't be built. Don't depend on them.
+ return
+ }
+
+ if l, ok := m.(lintOutputIntf); ok {
+ outputs = append(outputs, l.lintOutputs())
+ }
+ })
+
+ dirs = android.SortedUniqueStrings(dirs)
+
+ zip := func(outputPath android.WritablePath, get func(*lintOutputs) android.Path) {
+ var paths android.Paths
+
+ for _, output := range outputs {
+ paths = append(paths, get(output))
+ }
+
+ sort.Slice(paths, func(i, j int) bool {
+ return paths[i].String() < paths[j].String()
+ })
+
+ rule := android.NewRuleBuilder()
+
+ rule.Command().BuiltTool(ctx, "soong_zip").
+ FlagWithOutput("-o ", outputPath).
+ FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
+ FlagWithRspFileInputList("-l ", paths)
+
+ rule.Build(pctx, ctx, outputPath.Base(), outputPath.Base())
+ }
+
+ l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip")
+ zip(l.htmlZip, func(l *lintOutputs) android.Path { return l.html })
+
+ l.textZip = android.PathForOutput(ctx, "lint-report-text.zip")
+ zip(l.textZip, func(l *lintOutputs) android.Path { return l.text })
+
+ l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip")
+ zip(l.xmlZip, func(l *lintOutputs) android.Path { return l.xml })
+
+ ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip)
+}
+
+func (l *lintSingleton) MakeVars(ctx android.MakeVarsContext) {
+ ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip)
+}
+
+var _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil)
+
+func init() {
+ android.RegisterSingletonType("lint",
+ func() android.Singleton { return &lintSingleton{} })
+}
diff --git a/java/lint_defaults.txt b/java/lint_defaults.txt
new file mode 100644
index 0000000..0786b7c
--- /dev/null
+++ b/java/lint_defaults.txt
@@ -0,0 +1,78 @@
+# Treat LintError as fatal to catch invocation errors
+--fatal_check LintError
+
+# Downgrade existing errors to warnings
+--warning_check AppCompatResource # 55 occurences in 10 modules
+--warning_check AppLinkUrlError # 111 occurences in 53 modules
+--warning_check BlockedPrivateApi # 2 occurences in 2 modules
+--warning_check ByteOrderMark # 2 occurences in 2 modules
+--warning_check DuplicateActivity # 3 occurences in 3 modules
+--warning_check DuplicateDefinition # 3623 occurences in 48 modules
+--warning_check DuplicateIds # 207 occurences in 22 modules
+--warning_check EllipsizeMaxLines # 12 occurences in 7 modules
+--warning_check ExtraTranslation # 21276 occurences in 27 modules
+--warning_check FontValidationError # 4 occurences in 1 modules
+--warning_check FullBackupContent # 16 occurences in 1 modules
+--warning_check GetContentDescriptionOverride # 3 occurences in 2 modules
+--warning_check HalfFloat # 31 occurences in 1 modules
+--warning_check HardcodedDebugMode # 99 occurences in 95 modules
+--warning_check ImpliedQuantity # 703 occurences in 27 modules
+--warning_check ImpliedTouchscreenHardware # 4 occurences in 4 modules
+--warning_check IncludeLayoutParam # 11 occurences in 6 modules
+--warning_check Instantiatable # 145 occurences in 19 modules
+--warning_check InvalidPermission # 6 occurences in 4 modules
+--warning_check InvalidUsesTagAttribute # 6 occurences in 2 modules
+--warning_check InvalidWakeLockTag # 111 occurences in 37 modules
+--warning_check JavascriptInterface # 3 occurences in 2 modules
+--warning_check LibraryCustomView # 9 occurences in 4 modules
+--warning_check LogTagMismatch # 81 occurences in 13 modules
+--warning_check LongLogTag # 249 occurences in 12 modules
+--warning_check MenuTitle # 5 occurences in 4 modules
+--warning_check MissingClass # 537 occurences in 141 modules
+--warning_check MissingConstraints # 39 occurences in 10 modules
+--warning_check MissingDefaultResource # 1257 occurences in 40 modules
+--warning_check MissingIntentFilterForMediaSearch # 1 occurences in 1 modules
+--warning_check MissingLeanbackLauncher # 3 occurences in 3 modules
+--warning_check MissingLeanbackSupport # 2 occurences in 2 modules
+--warning_check MissingOnPlayFromSearch # 1 occurences in 1 modules
+--warning_check MissingPermission # 2071 occurences in 150 modules
+--warning_check MissingPrefix # 46 occurences in 41 modules
+--warning_check MissingQuantity # 100 occurences in 1 modules
+--warning_check MissingSuperCall # 121 occurences in 36 modules
+--warning_check MissingTvBanner # 3 occurences in 3 modules
+--warning_check NamespaceTypo # 3 occurences in 3 modules
+--warning_check NetworkSecurityConfig # 46 occurences in 12 modules
+--warning_check NewApi # 1996 occurences in 122 modules
+--warning_check NotSibling # 15 occurences in 10 modules
+--warning_check ObjectAnimatorBinding # 14 occurences in 5 modules
+--warning_check OnClick # 49 occurences in 21 modules
+--warning_check Orientation # 77 occurences in 19 modules
+--warning_check Override # 385 occurences in 36 modules
+--warning_check ParcelCreator # 23 occurences in 2 modules
+--warning_check ProtectedPermissions # 2413 occurences in 381 modules
+--warning_check Range # 80 occurences in 28 modules
+--warning_check RecyclerView # 1 occurences in 1 modules
+--warning_check ReferenceType # 4 occurences in 1 modules
+--warning_check ResourceAsColor # 19 occurences in 14 modules
+--warning_check RequiredSize # 52 occurences in 13 modules
+--warning_check ResAuto # 3 occurences in 1 modules
+--warning_check ResourceCycle # 37 occurences in 10 modules
+--warning_check ResourceType # 137 occurences in 36 modules
+--warning_check RestrictedApi # 28 occurences in 5 modules
+--warning_check RtlCompat # 9 occurences in 6 modules
+--warning_check ServiceCast # 3 occurences in 1 modules
+--warning_check SoonBlockedPrivateApi # 5 occurences in 3 modules
+--warning_check StringFormatInvalid # 148 occurences in 11 modules
+--warning_check StringFormatMatches # 4800 occurences in 30 modules
+--warning_check UnknownId # 8 occurences in 7 modules
+--warning_check ValidFragment # 12 occurences in 5 modules
+--warning_check ValidRestrictions # 5 occurences in 1 modules
+--warning_check WebViewLayout # 3 occurences in 1 modules
+--warning_check WrongCall # 21 occurences in 3 modules
+--warning_check WrongConstant # 894 occurences in 126 modules
+--warning_check WrongManifestParent # 10 occurences in 4 modules
+--warning_check WrongThread # 14 occurences in 6 modules
+--warning_check WrongViewCast # 1 occurences in 1 modules
+
+# TODO(b/158390965): remove this when lint doesn't crash
+--disable_check HardcodedDebugMode
diff --git a/java/plugin.go b/java/plugin.go
index a5e8292..947c286 100644
--- a/java/plugin.go
+++ b/java/plugin.go
@@ -24,10 +24,8 @@
func PluginFactory() android.Module {
module := &Plugin{}
- module.AddProperties(
- &module.Module.properties,
- &module.Module.protoProperties,
- &module.pluginProperties)
+ module.addHostProperties()
+ module.AddProperties(&module.pluginProperties)
InitJavaModule(module, android.HostSupported)
return module
diff --git a/java/robolectric.go b/java/robolectric.go
index 3195615..c6b07a1 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -215,13 +215,13 @@
func RobolectricTestFactory() android.Module {
module := &robolectricTest{}
+ module.addHostProperties()
module.AddProperties(
- &module.Module.properties,
&module.Module.deviceProperties,
- &module.Module.protoProperties,
&module.robolectricProperties)
module.Module.dexpreopter.isTest = true
+ module.Module.linter.test = true
InitJavaModule(module, android.DeviceSupported)
return module
diff --git a/java/sdk_library.go b/java/sdk_library.go
index de5ee03..676557e 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -264,7 +264,7 @@
apiScopeModuleLib = initApiScope(&apiScope{
name: "module-lib",
extends: apiScopeSystem,
- // Module_lib scope is disabled by default in legacy mode.
+ // The module-lib scope is disabled by default in legacy mode.
//
// Enabling this would break existing usages.
legacyEnabledStatus: func(module *SdkLibrary) bool {
@@ -280,11 +280,34 @@
"--show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES\\)",
},
})
+ apiScopeSystemServer = initApiScope(&apiScope{
+ name: "system-server",
+ extends: apiScopePublic,
+ // The system-server scope is disabled by default in legacy mode.
+ //
+ // Enabling this would break existing usages.
+ legacyEnabledStatus: func(module *SdkLibrary) bool {
+ return false
+ },
+ scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties {
+ return &module.sdkLibraryProperties.System_server
+ },
+ apiFilePrefix: "system-server-",
+ moduleSuffix: ".system_server",
+ sdkVersion: "system_server_current",
+ droidstubsArgs: []string{
+ "--show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.SYSTEM_SERVER\\) ",
+ "--hide-annotation android.annotation.Hide",
+ // com.android.* classes are okay in this interface"
+ "--hide InternalClasses",
+ },
+ })
allApiScopes = apiScopes{
apiScopePublic,
apiScopeSystem,
apiScopeTest,
apiScopeModuleLib,
+ apiScopeSystemServer,
}
)
@@ -429,12 +452,18 @@
// In non-legacy mode the test api scope is disabled by default.
Test ApiScopeProperties
- // The properties specific to the module_lib api scope
+ // The properties specific to the module-lib api scope
//
- // Unless explicitly specified by using test.enabled the module_lib api scope is
+ // Unless explicitly specified by using test.enabled the module-lib api scope is
// disabled by default.
Module_lib ApiScopeProperties
+ // The properties specific to the system-server api scope
+ //
+ // Unless explicitly specified by using test.enabled the module-lib api scope is
+ // disabled by default.
+ System_server ApiScopeProperties
+
// Determines if the stubs are preferred over the implementation library
// for linking, even when the client doesn't specify sdk_version. When this
// is set to true, such clients are provided with the widest API surface that
@@ -600,6 +629,16 @@
return true
}
+// Module name of the runtime implementation library
+func (c *commonToSdkLibraryAndImport) implLibraryModuleName() string {
+ return c.moduleBase.BaseModuleName() + ".impl"
+}
+
+// Module name of the XML file for the lib
+func (c *commonToSdkLibraryAndImport) xmlPermissionsModuleName() string {
+ return c.moduleBase.BaseModuleName() + sdkXmlFileSuffix
+}
+
// Name of the java_library module that compiles the stubs source.
func (c *commonToSdkLibraryAndImport) stubsLibraryModuleName(apiScope *apiScope) string {
return c.namingScheme.stubsLibraryModuleName(apiScope, c.moduleBase.BaseModuleName())
@@ -743,6 +782,8 @@
apiScope = apiScopeModuleLib
case sdkTest:
apiScope = apiScopeTest
+ case sdkSystemServer:
+ apiScope = apiScopeSystemServer
default:
apiScope = apiScopePublic
}
@@ -827,7 +868,7 @@
var _ SdkLibraryComponentDependency = (*Library)(nil)
var _ SdkLibraryComponentDependency = (*Import)(nil)
var _ SdkLibraryComponentDependency = (*SdkLibrary)(nil)
-var _ SdkLibraryComponentDependency = (*sdkLibraryImport)(nil)
+var _ SdkLibraryComponentDependency = (*SdkLibraryImport)(nil)
// Provides access to sdk_version related header and implentation jars.
type SdkLibraryDependency interface {
@@ -913,16 +954,24 @@
return generatedScopes
}
-var xmlPermissionsFileTag = dependencyTag{name: "xml-permissions-file"}
+type sdkLibraryComponentTag struct {
+ blueprint.BaseDependencyTag
+ name string
+}
+
+// Mark this tag so dependencies that use it are excluded from visibility enforcement.
+func (t sdkLibraryComponentTag) ExcludeFromVisibilityEnforcement() {}
+
+var xmlPermissionsFileTag = sdkLibraryComponentTag{name: "xml-permissions-file"}
func IsXmlPermissionsFileDepTag(depTag blueprint.DependencyTag) bool {
- if dt, ok := depTag.(dependencyTag); ok {
+ if dt, ok := depTag.(sdkLibraryComponentTag); ok {
return dt == xmlPermissionsFileTag
}
return false
}
-var implLibraryTag = dependencyTag{name: "impl-library"}
+var implLibraryTag = sdkLibraryComponentTag{name: "impl-library"}
func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
for _, apiScope := range module.getGeneratedApiScopes(ctx) {
@@ -947,7 +996,7 @@
if module.sharedLibrary() {
// Add dependency to the rule for generating the xml permissions file
- ctx.AddDependency(module, xmlPermissionsFileTag, module.xmlFileName())
+ ctx.AddDependency(module, xmlPermissionsFileTag, module.xmlPermissionsModuleName())
}
// Only add the deps for the library if it is actually going to be built.
@@ -993,21 +1042,13 @@
return nil
}
entriesList := module.Library.AndroidMkEntries()
- entries := &entriesList[0]
- entries.Required = append(entries.Required, module.xmlFileName())
+ if module.sharedLibrary() {
+ entries := &entriesList[0]
+ entries.Required = append(entries.Required, module.xmlPermissionsModuleName())
+ }
return entriesList
}
-// Module name of the runtime implementation library
-func (module *SdkLibrary) implLibraryModuleName() string {
- return module.BaseModuleName() + ".impl"
-}
-
-// Module name of the XML file for the lib
-func (module *SdkLibrary) xmlFileName() string {
- return module.BaseModuleName() + sdkXmlFileSuffix
-}
-
// The dist path of the stub artifacts
func (module *SdkLibrary) apiDistPath(apiScope *apiScope) string {
if module.ModuleBase.Owner() != "" {
@@ -1049,9 +1090,12 @@
props := struct {
Name *string
Visibility []string
+ Instrument bool
}{
Name: proptools.StringPtr(module.implLibraryModuleName()),
Visibility: module.sdkLibraryProperties.Impl_library_visibility,
+ // Set the instrument property to ensure it is instrumented when instrumentation is required.
+ Instrument: true,
}
properties := []interface{}{
@@ -1059,6 +1103,7 @@
&module.protoProperties,
&module.deviceProperties,
&module.dexpreoptProperties,
+ &module.linter.properties,
&props,
module.sdkComponentPropertiesForChildLibrary(),
}
@@ -1298,7 +1343,7 @@
Lib_name *string
Apex_available []string
}{
- Name: proptools.StringPtr(module.xmlFileName()),
+ Name: proptools.StringPtr(module.xmlPermissionsModuleName()),
Lib_name: proptools.StringPtr(module.BaseModuleName()),
Apex_available: module.ApexProperties.Apex_available,
}
@@ -1346,7 +1391,7 @@
//
// If either this or the other module are on the platform then this will return
// false.
-func (module *SdkLibrary) withinSameApexAs(other android.Module) bool {
+func withinSameApexAs(module android.ApexModule, other android.Module) bool {
name := module.ApexName()
return name != "" && getApexNameForModule(other) == name
}
@@ -1367,7 +1412,7 @@
// Only allow access to the implementation library in the following condition:
// * No sdk_version specified on the referencing module.
// * The referencing module is in the same apex as this.
- if sdkVersion.kind == sdkPrivate || module.withinSameApexAs(ctx.Module()) {
+ if sdkVersion.kind == sdkPrivate || withinSameApexAs(module, ctx.Module()) {
if headerJars {
return module.HeaderJars()
} else {
@@ -1504,13 +1549,8 @@
}
func (module *SdkLibrary) InitSdkLibraryProperties() {
- module.AddProperties(
- &module.sdkLibraryProperties,
- &module.properties,
- &module.dexpreoptProperties,
- &module.deviceProperties,
- &module.protoProperties,
- )
+ module.addHostAndDeviceProperties()
+ module.AddProperties(&module.sdkLibraryProperties)
module.initSdkLibraryComponent(&module.ModuleBase)
@@ -1671,7 +1711,7 @@
Libs []string
}
-type sdkLibraryImport struct {
+type SdkLibraryImport struct {
android.ModuleBase
android.DefaultableModuleBase
prebuilt android.Prebuilt
@@ -1684,9 +1724,17 @@
scopeProperties map[*apiScope]*sdkLibraryScopeProperties
commonToSdkLibraryAndImport
+
+ // The reference to the implementation library created by the source module.
+ // Is nil if the source module does not exist.
+ implLibraryModule *Library
+
+ // The reference to the xml permissions module created by the source module.
+ // Is nil if the source module does not exist.
+ xmlPermissionsFileModule *sdkLibraryXml
}
-var _ SdkLibraryDependency = (*sdkLibraryImport)(nil)
+var _ SdkLibraryDependency = (*SdkLibraryImport)(nil)
// The type of a structure that contains a field of type sdkLibraryScopeProperties
// for each apiscope in allApiScopes, e.g. something like:
@@ -1728,7 +1776,7 @@
// java_sdk_library_import imports a prebuilt java_sdk_library.
func sdkLibraryImportFactory() android.Module {
- module := &sdkLibraryImport{}
+ module := &SdkLibraryImport{}
allScopeProperties, scopeToProperties := createPropertiesInstance()
module.scopeProperties = scopeToProperties
@@ -1750,15 +1798,15 @@
return module
}
-func (module *sdkLibraryImport) Prebuilt() *android.Prebuilt {
+func (module *SdkLibraryImport) Prebuilt() *android.Prebuilt {
return &module.prebuilt
}
-func (module *sdkLibraryImport) Name() string {
+func (module *SdkLibraryImport) Name() string {
return module.prebuilt.Name(module.ModuleBase.Name())
}
-func (module *sdkLibraryImport) createInternalModules(mctx android.DefaultableHookContext) {
+func (module *SdkLibraryImport) createInternalModules(mctx android.DefaultableHookContext) {
// If the build is configured to use prebuilts then force this to be preferred.
if mctx.Config().UnbundledBuildUsePrebuiltSdks() {
@@ -1783,7 +1831,7 @@
*javaSdkLibraries = append(*javaSdkLibraries, module.BaseModuleName())
}
-func (module *sdkLibraryImport) createJavaImportForStubs(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
+func (module *SdkLibraryImport) createJavaImportForStubs(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
// Creates a java import for the jar with ".stubs" suffix
props := struct {
Name *string
@@ -1805,7 +1853,7 @@
mctx.CreateModule(ImportFactory, &props, module.sdkComponentPropertiesForChildLibrary())
}
-func (module *sdkLibraryImport) createPrebuiltStubsSources(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
+func (module *SdkLibraryImport) createPrebuiltStubsSources(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
props := struct {
Name *string
Srcs []string
@@ -1819,7 +1867,7 @@
props.Prefer = proptools.BoolPtr(module.prebuilt.Prefer())
}
-func (module *sdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext) {
+func (module *SdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext) {
for apiScope, scopeProperties := range module.scopeProperties {
if len(scopeProperties.Jars) == 0 {
continue
@@ -1833,13 +1881,35 @@
ctx.AddVariationDependencies(nil, apiScope.stubsSourceTag, module.stubsSourceModuleName(apiScope))
}
}
+
+ implName := module.implLibraryModuleName()
+ if ctx.OtherModuleExists(implName) {
+ ctx.AddVariationDependencies(nil, implLibraryTag, implName)
+
+ xmlPermissionsModuleName := module.xmlPermissionsModuleName()
+ if module.sharedLibrary() && ctx.OtherModuleExists(xmlPermissionsModuleName) {
+ // Add dependency to the rule for generating the xml permissions file
+ ctx.AddDependency(module, xmlPermissionsFileTag, xmlPermissionsModuleName)
+ }
+ }
}
-func (module *sdkLibraryImport) OutputFiles(tag string) (android.Paths, error) {
+func (module *SdkLibraryImport) DepIsInSameApex(mctx android.BaseModuleContext, dep android.Module) bool {
+ depTag := mctx.OtherModuleDependencyTag(dep)
+ if depTag == xmlPermissionsFileTag {
+ return true
+ }
+
+ // None of the other dependencies of the java_sdk_library_import are in the same apex
+ // as the one that references this module.
+ return false
+}
+
+func (module *SdkLibraryImport) OutputFiles(tag string) (android.Paths, error) {
return module.commonOutputFiles(tag)
}
-func (module *sdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
// Record the paths to the prebuilt stubs library and stubs source.
ctx.VisitDirectDeps(func(to android.Module) {
tag := ctx.OtherModuleDependencyTag(to)
@@ -1852,6 +1922,18 @@
// Extract information from the dependency. The exact information extracted
// is determined by the nature of the dependency which is determined by the tag.
scopeTag.extractDepInfo(ctx, to, scopePaths)
+ } else if tag == implLibraryTag {
+ if implLibrary, ok := to.(*Library); ok {
+ module.implLibraryModule = implLibrary
+ } else {
+ ctx.ModuleErrorf("implementation library must be of type *java.Library but was %T", to)
+ }
+ } else if tag == xmlPermissionsFileTag {
+ if xmlPermissionsFileModule, ok := to.(*sdkLibraryXml); ok {
+ module.xmlPermissionsFileModule = xmlPermissionsFileModule
+ } else {
+ ctx.ModuleErrorf("xml permissions file module must be of type *sdkLibraryXml but was %T", to)
+ }
}
})
@@ -1867,20 +1949,75 @@
}
}
-func (module *sdkLibraryImport) sdkJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths {
+func (module *SdkLibraryImport) sdkJars(ctx android.BaseModuleContext, sdkVersion sdkSpec, headerJars bool) android.Paths {
+
+ // For consistency with SdkLibrary make the implementation jar available to libraries that
+ // are within the same APEX.
+ implLibraryModule := module.implLibraryModule
+ if implLibraryModule != nil && withinSameApexAs(module, ctx.Module()) {
+ if headerJars {
+ return implLibraryModule.HeaderJars()
+ } else {
+ return implLibraryModule.ImplementationJars()
+ }
+ }
+
return module.selectHeaderJarsForSdkVersion(ctx, sdkVersion)
}
// to satisfy SdkLibraryDependency interface
-func (module *sdkLibraryImport) SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths {
+func (module *SdkLibraryImport) SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths {
// This module is just a wrapper for the prebuilt stubs.
- return module.sdkJars(ctx, sdkVersion)
+ return module.sdkJars(ctx, sdkVersion, true)
}
// to satisfy SdkLibraryDependency interface
-func (module *sdkLibraryImport) SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths {
+func (module *SdkLibraryImport) SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths {
// This module is just a wrapper for the stubs.
- return module.sdkJars(ctx, sdkVersion)
+ return module.sdkJars(ctx, sdkVersion, false)
+}
+
+// to satisfy apex.javaDependency interface
+func (module *SdkLibraryImport) DexJarBuildPath() android.Path {
+ if module.implLibraryModule == nil {
+ return nil
+ } else {
+ return module.implLibraryModule.DexJarBuildPath()
+ }
+}
+
+// to satisfy apex.javaDependency interface
+func (module *SdkLibraryImport) JacocoReportClassesFile() android.Path {
+ if module.implLibraryModule == nil {
+ return nil
+ } else {
+ return module.implLibraryModule.JacocoReportClassesFile()
+ }
+}
+
+// to satisfy apex.javaDependency interface
+func (module *SdkLibraryImport) Stem() string {
+ return module.BaseModuleName()
+}
+
+var _ ApexDependency = (*SdkLibraryImport)(nil)
+
+// to satisfy java.ApexDependency interface
+func (module *SdkLibraryImport) HeaderJars() android.Paths {
+ if module.implLibraryModule == nil {
+ return nil
+ } else {
+ return module.implLibraryModule.HeaderJars()
+ }
+}
+
+// to satisfy java.ApexDependency interface
+func (module *SdkLibraryImport) ImplementationAndResourcesJars() android.Paths {
+ if module.implLibraryModule == nil {
+ return nil
+ } else {
+ return module.implLibraryModule.ImplementationAndResourcesJars()
+ }
}
//
@@ -2056,8 +2193,12 @@
properties.Jars = jars
properties.SdkVersion = sdk.sdkVersionForStubsLibrary(ctx.SdkModuleContext(), apiScope)
properties.StubsSrcJar = paths.stubsSrcJar.Path()
- properties.CurrentApiFile = paths.currentApiFilePath.Path()
- properties.RemovedApiFile = paths.removedApiFilePath.Path()
+ if paths.currentApiFilePath.Valid() {
+ properties.CurrentApiFile = paths.currentApiFilePath.Path()
+ }
+ if paths.removedApiFilePath.Valid() {
+ properties.RemovedApiFile = paths.removedApiFilePath.Path()
+ }
s.Scopes[apiScope] = properties
}
}
diff --git a/java/testing.go b/java/testing.go
index f34c64a..6fc10da 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -80,6 +80,13 @@
"prebuilts/sdk/30/test/api/bar-removed.txt": nil,
"prebuilts/sdk/tools/core-lambda-stubs.jar": nil,
"prebuilts/sdk/Android.bp": []byte(`prebuilt_apis { name: "sdk", api_dirs: ["14", "28", "30", "current"],}`),
+
+ // For java_sdk_library
+ "api/module-lib-current.txt": nil,
+ "api/module-lib-removed.txt": nil,
+ "api/system-server-current.txt": nil,
+ "api/system-server-removed.txt": nil,
+ "build/soong/scripts/gen-java-current-api-files.sh": nil,
}
cc.GatherRequiredFilesForTest(mockFS)
diff --git a/python/python.go b/python/python.go
index 8b912be..a6c9e2a 100644
--- a/python/python.go
+++ b/python/python.go
@@ -251,6 +251,18 @@
return android.OptionalPathForPath(p.installer.(*binaryDecorator).path)
}
+func (p *Module) OutputFiles(tag string) (android.Paths, error) {
+ switch tag {
+ case "":
+ if outputFile := p.installSource; outputFile.Valid() {
+ return android.Paths{outputFile.Path()}, nil
+ }
+ return android.Paths{}, nil
+ default:
+ return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+ }
+}
+
func (p *Module) isEmbeddedLauncherEnabled(actual_version string) bool {
switch actual_version {
case pyVersion2:
diff --git a/rust/binary.go b/rust/binary.go
index c25ae09..56d6f0b 100644
--- a/rust/binary.go
+++ b/rust/binary.go
@@ -24,9 +24,6 @@
}
type BinaryCompilerProperties struct {
- // path to the main source file that contains the program entry point (e.g. src/main.rs)
- Srcs []string `android:"path,arch_variant"`
-
// passes -C prefer-dynamic to rustc, which tells it to dynamically link the stdlib
// (assuming it has no dylib dependencies already)
Prefer_dynamic *bool
@@ -35,10 +32,7 @@
type binaryDecorator struct {
*baseCompiler
- Properties BinaryCompilerProperties
- distFile android.OptionalPath
- coverageOutputZipFile android.OptionalPath
- unstrippedOutputFile android.Path
+ Properties BinaryCompilerProperties
}
var _ compiler = (*binaryDecorator)(nil)
@@ -112,7 +106,7 @@
func (binary *binaryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
fileName := binary.getStem(ctx) + ctx.toolchain().ExecutableSuffix()
- srcPath := srcPathFromModuleSrcs(ctx, binary.Properties.Srcs)
+ srcPath := srcPathFromModuleSrcs(ctx, binary.baseCompiler.Properties.Srcs)
outputFile := android.PathForModuleOut(ctx, fileName)
binary.unstrippedOutputFile = outputFile
diff --git a/rust/builder.go b/rust/builder.go
index 5069b07..7dbb59d 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -163,7 +163,7 @@
if flags.Coverage {
var gcnoFile android.WritablePath
// Provide consistency with cc gcda output, see cc/builder.go init()
- profileEmitArg := strings.TrimPrefix("PWD=", cc.PwdPrefix()) + "/"
+ profileEmitArg := strings.TrimPrefix(cc.PwdPrefix(), "PWD=") + "/"
if outputFile.Ext() != "" {
gcnoFile = android.PathForModuleOut(ctx, pathtools.ReplaceExtension(outputFile.Base(), "gcno"))
diff --git a/rust/compiler.go b/rust/compiler.go
index 5f098bc..efc1ce4 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -53,6 +53,9 @@
)
type BaseCompilerProperties struct {
+ // path to the source file that is the main entry point of the program (e.g. main.rs or lib.rs)
+ Srcs []string `android:"path,arch_variant"`
+
// whether to pass "-D warnings" to rustc. Defaults to true.
Deny_warnings *bool
@@ -100,17 +103,10 @@
}
type baseCompiler struct {
- Properties BaseCompilerProperties
- pathDeps android.Paths
- rustFlagsDeps android.Paths
- linkFlagsDeps android.Paths
- flags string
- linkFlags string
- depFlags []string
- linkDirs []string
- edition string
- src android.Path //rustc takes a single src file
- coverageFile android.Path //rustc generates a single gcno file
+ Properties BaseCompilerProperties
+ depFlags []string
+ linkDirs []string
+ coverageFile android.Path //rustc generates a single gcno file
// Install related
dir string
@@ -119,6 +115,10 @@
relative string
path android.InstallPath
location installLocation
+
+ coverageOutputZipFile android.OptionalPath
+ unstrippedOutputFile android.Path
+ distFile android.OptionalPath
}
func (compiler *baseCompiler) coverageOutputZipPath() android.OptionalPath {
diff --git a/rust/coverage.go b/rust/coverage.go
index 9be57dc..4e3977b 100644
--- a/rust/coverage.go
+++ b/rust/coverage.go
@@ -45,7 +45,7 @@
func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) {
- if !ctx.DeviceConfig().NativeCoverageEnabled() && !ctx.DeviceConfig().ClangCoverageEnabled() {
+ if !ctx.DeviceConfig().NativeCoverageEnabled() {
return flags, deps
}
diff --git a/rust/library.go b/rust/library.go
index 2e51266..3c948ea 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -45,9 +45,6 @@
Shared VariantLibraryProperties `android:"arch_variant"`
Static VariantLibraryProperties `android:"arch_variant"`
- // path to the source file that is the main entry point of the program (e.g. src/lib.rs)
- Srcs []string `android:"path,arch_variant"`
-
// path to include directories to pass to cc_* modules, only relevant for static/shared variants.
Include_dirs []string `android:"path,arch_variant"`
}
@@ -75,12 +72,9 @@
type libraryDecorator struct {
*baseCompiler
- Properties LibraryCompilerProperties
- MutatedProperties LibraryMutatedProperties
- distFile android.OptionalPath
- coverageOutputZipFile android.OptionalPath
- unstrippedOutputFile android.Path
- includeDirs android.Paths
+ Properties LibraryCompilerProperties
+ MutatedProperties LibraryMutatedProperties
+ includeDirs android.Paths
}
type libraryInterface interface {
@@ -311,8 +305,8 @@
func (library *libraryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps {
- // TODO(b/144861059) Remove if C libraries support dylib linkage in the future.
- if !ctx.Host() && (library.static() || library.shared()) {
+ // TODO(b/155498724) Remove if C static libraries no longer require libstd as an rlib dependency.
+ if !ctx.Host() && library.static() {
library.setNoStdlibs()
for _, stdlib := range config.Stdlibs {
deps.Rlibs = append(deps.Rlibs, stdlib+".static")
@@ -350,7 +344,7 @@
func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
var outputFile android.WritablePath
- srcPath := srcPathFromModuleSrcs(ctx, library.Properties.Srcs)
+ srcPath := srcPathFromModuleSrcs(ctx, library.baseCompiler.Properties.Srcs)
flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
diff --git a/rust/library_test.go b/rust/library_test.go
index 37dd541..9d2f6c0 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -17,6 +17,8 @@
import (
"strings"
"testing"
+
+ "android/soong/android"
)
// Test that variants are being generated correctly, and that crate-types are correct.
@@ -115,16 +117,24 @@
}
-func TestSharedLibraryFlags(t *testing.T) {
+func TestSharedLibrary(t *testing.T) {
ctx := testRust(t, `
- rust_library_host {
+ rust_library {
name: "libfoo",
srcs: ["foo.rs"],
crate_name: "foo",
}`)
- libfooShared := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_shared").Output("libfoo.so")
- if !strings.Contains(libfooShared.Args["linkFlags"], "-Wl,-soname=libfoo.so") {
- t.Errorf("missing expected -Wl,-soname linker flag for libfoo shared lib, linkFlags: %#v", libfooShared.Args["linkFlags"])
+ libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared")
+
+ libfooOutput := libfoo.Output("libfoo.so")
+ if !strings.Contains(libfooOutput.Args["linkFlags"], "-Wl,-soname=libfoo.so") {
+ t.Errorf("missing expected -Wl,-soname linker flag for libfoo shared lib, linkFlags: %#v",
+ libfooOutput.Args["linkFlags"])
+ }
+
+ if !android.InList("libstd", libfoo.Module().(*Module).Properties.AndroidMkDylibs) {
+ t.Errorf("Non-static libstd dylib expected to be a dependency of Rust shared libraries. Dylib deps are: %#v",
+ libfoo.Module().(*Module).Properties.AndroidMkDylibs)
}
}
diff --git a/rust/proc_macro.go b/rust/proc_macro.go
index 10ea1e3..42c8537 100644
--- a/rust/proc_macro.go
+++ b/rust/proc_macro.go
@@ -23,20 +23,12 @@
}
type ProcMacroCompilerProperties struct {
- // path to the source file that is the main entry point of the program (e.g. src/lib.rs)
- Srcs []string `android:"path,arch_variant"`
-
- // set name of the procMacro
- Stem *string `android:"arch_variant"`
- Suffix *string `android:"arch_variant"`
}
type procMacroDecorator struct {
*baseCompiler
- Properties ProcMacroCompilerProperties
- distFile android.OptionalPath
- unstrippedOutputFile android.Path
+ Properties ProcMacroCompilerProperties
}
type procMacroInterface interface {
@@ -70,7 +62,7 @@
fileName := procMacro.getStem(ctx) + ctx.toolchain().ProcMacroSuffix()
outputFile := android.PathForModuleOut(ctx, fileName)
- srcPath := srcPathFromModuleSrcs(ctx, procMacro.Properties.Srcs)
+ srcPath := srcPathFromModuleSrcs(ctx, procMacro.baseCompiler.Properties.Srcs)
procMacro.unstrippedOutputFile = outputFile
diff --git a/rust/project_json.go b/rust/project_json.go
index 909aebc..a50e73a 100644
--- a/rust/project_json.go
+++ b/rust/project_json.go
@@ -114,7 +114,7 @@
return cInfo.ID, crateName, true
}
crate := rustProjectCrate{Deps: make([]rustProjectDep, 0), Cfgs: make([]string, 0)}
- src := rustLib.Properties.Srcs[0]
+ src := rustLib.baseCompiler.Properties.Srcs[0]
crate.RootModule = path.Join(ctx.ModuleDir(rModule), src)
crate.Edition = getEdition(rustLib.baseCompiler)
diff --git a/rust/rust.go b/rust/rust.go
index 6671dd3..7b82b1f 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -45,11 +45,10 @@
}
type Flags struct {
- GlobalRustFlags []string // Flags that apply globally to rust
- GlobalLinkFlags []string // Flags that apply globally to linker
- RustFlags []string // Flags that apply to rust
- LinkFlags []string // Flags that apply to linker
- RustFlagsDeps android.Paths // Files depended on by compiler flags
+ GlobalRustFlags []string // Flags that apply globally to rust
+ GlobalLinkFlags []string // Flags that apply globally to linker
+ RustFlags []string // Flags that apply to rust
+ LinkFlags []string // Flags that apply to linker
Toolchain config.Toolchain
Coverage bool
}
@@ -196,6 +195,10 @@
return false
}
+func (mod *Module) IsSdkVariant() bool {
+ return false
+}
+
func (mod *Module) ToolchainLibrary() bool {
return false
}
diff --git a/rust/rust_test.go b/rust/rust_test.go
index d658ee2..703aaed 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -88,8 +88,9 @@
config := testConfig(bp)
if coverage {
+ config.TestProductVariables.GcovCoverage = proptools.BoolPtr(true)
config.TestProductVariables.Native_coverage = proptools.BoolPtr(true)
- config.TestProductVariables.CoveragePaths = []string{"*"}
+ config.TestProductVariables.NativeCoveragePaths = []string{"*"}
}
t.Helper()
diff --git a/rust/test.go b/rust/test.go
index f616c06..416c557 100644
--- a/rust/test.go
+++ b/rust/test.go
@@ -57,7 +57,14 @@
}
func NewRustTest(hod android.HostOrDeviceSupported) (*Module, *testDecorator) {
- module := newModule(hod, android.MultilibFirst)
+ // Build both 32 and 64 targets for device tests.
+ // Cannot build both for host tests yet if the test depends on
+ // something like proc-macro2 that cannot be built for both.
+ multilib := android.MultilibBoth
+ if hod != android.DeviceSupported && hod != android.HostAndDeviceSupported {
+ multilib = android.MultilibFirst
+ }
+ module := newModule(hod, multilib)
test := &testDecorator{
binaryDecorator: &binaryDecorator{
diff --git a/scripts/Android.bp b/scripts/Android.bp
index e848b50..1f55030 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -148,3 +148,9 @@
],
test_suites: ["general-tests"],
}
+
+python_binary_host {
+ name: "lint-project-xml",
+ main: "lint-project-xml.py",
+ srcs: ["lint-project-xml.py"],
+}
diff --git a/scripts/build-mainline-modules.sh b/scripts/build-mainline-modules.sh
index df763c8..9b68a82 100755
--- a/scripts/build-mainline-modules.sh
+++ b/scripts/build-mainline-modules.sh
@@ -21,6 +21,8 @@
conscrypt-module-host-exports
runtime-module-sdk
runtime-module-host-exports
+ i18n-module-test-exports
+ i18n-module-sdk
)
# We want to create apex modules for all supported architectures.
diff --git a/scripts/lint-project-xml.py b/scripts/lint-project-xml.py
new file mode 100755
index 0000000..38c57ca
--- /dev/null
+++ b/scripts/lint-project-xml.py
@@ -0,0 +1,217 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# 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.
+#
+
+"""This file generates project.xml and lint.xml files used to drive the Android Lint CLI tool."""
+
+import argparse
+
+
+def check_action(check_type):
+ """
+ Returns an action that appends a tuple of check_type and the argument to the dest.
+ """
+ class CheckAction(argparse.Action):
+ def __init__(self, option_strings, dest, nargs=None, **kwargs):
+ if nargs is not None:
+ raise ValueError("nargs must be None, was %s" % nargs)
+ super(CheckAction, self).__init__(option_strings, dest, **kwargs)
+ def __call__(self, parser, namespace, values, option_string=None):
+ checks = getattr(namespace, self.dest, [])
+ checks.append((check_type, values))
+ setattr(namespace, self.dest, checks)
+ return CheckAction
+
+
+def parse_args():
+ """Parse commandline arguments."""
+
+ def convert_arg_line_to_args(arg_line):
+ for arg in arg_line.split():
+ if arg.startswith('#'):
+ return
+ if not arg.strip():
+ continue
+ yield arg
+
+ parser = argparse.ArgumentParser(fromfile_prefix_chars='@')
+ parser.convert_arg_line_to_args = convert_arg_line_to_args
+ parser.add_argument('--project_out', dest='project_out',
+ help='file to which the project.xml contents will be written.')
+ parser.add_argument('--config_out', dest='config_out',
+ help='file to which the lint.xml contents will be written.')
+ parser.add_argument('--name', dest='name',
+ help='name of the module.')
+ parser.add_argument('--srcs', dest='srcs', action='append', default=[],
+ help='file containing whitespace separated list of source files.')
+ parser.add_argument('--generated_srcs', dest='generated_srcs', action='append', default=[],
+ help='file containing whitespace separated list of generated source files.')
+ parser.add_argument('--resources', dest='resources', action='append', default=[],
+ help='file containing whitespace separated list of resource files.')
+ parser.add_argument('--classes', dest='classes', action='append', default=[],
+ help='file containing the module\'s classes.')
+ parser.add_argument('--classpath', dest='classpath', action='append', default=[],
+ help='file containing classes from dependencies.')
+ parser.add_argument('--extra_checks_jar', dest='extra_checks_jars', action='append', default=[],
+ help='file containing extra lint checks.')
+ parser.add_argument('--manifest', dest='manifest',
+ help='file containing the module\'s manifest.')
+ parser.add_argument('--merged_manifest', dest='merged_manifest',
+ help='file containing merged manifest for the module and its dependencies.')
+ parser.add_argument('--library', dest='library', action='store_true',
+ help='mark the module as a library.')
+ parser.add_argument('--test', dest='test', action='store_true',
+ help='mark the module as a test.')
+ parser.add_argument('--cache_dir', dest='cache_dir',
+ help='directory to use for cached file.')
+ parser.add_argument('--root_dir', dest='root_dir',
+ help='directory to use for root dir.')
+ group = parser.add_argument_group('check arguments', 'later arguments override earlier ones.')
+ group.add_argument('--fatal_check', dest='checks', action=check_action('fatal'), default=[],
+ help='treat a lint issue as a fatal error.')
+ group.add_argument('--error_check', dest='checks', action=check_action('error'), default=[],
+ help='treat a lint issue as an error.')
+ group.add_argument('--warning_check', dest='checks', action=check_action('warning'), default=[],
+ help='treat a lint issue as a warning.')
+ group.add_argument('--disable_check', dest='checks', action=check_action('ignore'), default=[],
+ help='disable a lint issue.')
+ return parser.parse_args()
+
+
+class NinjaRspFileReader:
+ """
+ Reads entries from a Ninja rsp file. Ninja escapes any entries in the file that contain a
+ non-standard character by surrounding the whole entry with single quotes, and then replacing
+ any single quotes in the entry with the escape sequence '\''.
+ """
+
+ def __init__(self, filename):
+ self.f = open(filename, 'r')
+ self.r = self.character_reader(self.f)
+
+ def __iter__(self):
+ return self
+
+ def character_reader(self, f):
+ """Turns a file into a generator that returns one character at a time."""
+ while True:
+ c = f.read(1)
+ if c:
+ yield c
+ else:
+ return
+
+ def __next__(self):
+ entry = self.read_entry()
+ if entry:
+ return entry
+ else:
+ raise StopIteration
+
+ def read_entry(self):
+ c = next(self.r, "")
+ if not c:
+ return ""
+ elif c == "'":
+ return self.read_quoted_entry()
+ else:
+ entry = c
+ for c in self.r:
+ if c == " " or c == "\n":
+ break
+ entry += c
+ return entry
+
+ def read_quoted_entry(self):
+ entry = ""
+ for c in self.r:
+ if c == "'":
+ # Either the end of the quoted entry, or the beginning of an escape sequence, read the next
+ # character to find out.
+ c = next(self.r)
+ if not c or c == " " or c == "\n":
+ # End of the item
+ return entry
+ elif c == "\\":
+ # Escape sequence, expect a '
+ c = next(self.r)
+ if c != "'":
+ # Malformed escape sequence
+ raise "malformed escape sequence %s'\\%s" % (entry, c)
+ entry += "'"
+ else:
+ raise "malformed escape sequence %s'%s" % (entry, c)
+ else:
+ entry += c
+ raise "unterminated quoted entry %s" % entry
+
+
+def write_project_xml(f, args):
+ test_attr = "test='true' " if args.test else ""
+
+ f.write("<?xml version='1.0' encoding='utf-8'?>\n")
+ f.write("<project>\n")
+ if args.root_dir:
+ f.write(" <root dir='%s' />\n" % args.root_dir)
+ f.write(" <module name='%s' android='true' %sdesugar='full' >\n" % (args.name, "library='true' " if args.library else ""))
+ if args.manifest:
+ f.write(" <manifest file='%s' %s/>\n" % (args.manifest, test_attr))
+ if args.merged_manifest:
+ f.write(" <merged-manifest file='%s' %s/>\n" % (args.merged_manifest, test_attr))
+ for src_file in args.srcs:
+ for src in NinjaRspFileReader(src_file):
+ f.write(" <src file='%s' %s/>\n" % (src, test_attr))
+ for src_file in args.generated_srcs:
+ for src in NinjaRspFileReader(src_file):
+ f.write(" <src file='%s' generated='true' %s/>\n" % (src, test_attr))
+ for res_file in args.resources:
+ for res in NinjaRspFileReader(res_file):
+ f.write(" <resource file='%s' %s/>\n" % (res, test_attr))
+ for classes in args.classes:
+ f.write(" <classes jar='%s' />\n" % classes)
+ for classpath in args.classpath:
+ f.write(" <classpath jar='%s' />\n" % classpath)
+ for extra in args.extra_checks_jars:
+ f.write(" <lint-checks jar='%s' />\n" % extra)
+ f.write(" </module>\n")
+ if args.cache_dir:
+ f.write(" <cache dir='%s'/>\n" % args.cache_dir)
+ f.write("</project>\n")
+
+
+def write_config_xml(f, args):
+ f.write("<?xml version='1.0' encoding='utf-8'?>\n")
+ f.write("<lint>\n")
+ for check in args.checks:
+ f.write(" <issue id='%s' severity='%s' />\n" % (check[1], check[0]))
+ f.write("</lint>\n")
+
+
+def main():
+ """Program entry point."""
+ args = parse_args()
+
+ if args.project_out:
+ with open(args.project_out, 'w') as f:
+ write_project_xml(f, args)
+
+ if args.config_out:
+ with open(args.config_out, 'w') as f:
+ write_config_xml(f, args)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index 4a09081..123fe70 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -1976,3 +1976,83 @@
}
`))
}
+
+func TestUniqueHostSoname(t *testing.T) {
+ // b/145598135 - Generating host snapshots for anything other than linux is not supported.
+ SkipIfNotLinux(t)
+
+ result := testSdkWithCc(t, `
+ sdk {
+ name: "mysdk",
+ host_supported: true,
+ native_shared_libs: ["mylib"],
+ }
+
+ cc_library {
+ name: "mylib",
+ host_supported: true,
+ unique_host_soname: true,
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_shared {
+ name: "mysdk_mylib@current",
+ sdk_member_name: "mylib",
+ host_supported: true,
+ installable: false,
+ unique_host_soname: true,
+ target: {
+ android_arm64: {
+ srcs: ["android/arm64/lib/mylib.so"],
+ },
+ android_arm: {
+ srcs: ["android/arm/lib/mylib.so"],
+ },
+ linux_glibc_x86_64: {
+ srcs: ["linux_glibc/x86_64/lib/mylib-host.so"],
+ },
+ linux_glibc_x86: {
+ srcs: ["linux_glibc/x86/lib/mylib-host.so"],
+ },
+ },
+}
+
+cc_prebuilt_library_shared {
+ name: "mylib",
+ prefer: false,
+ host_supported: true,
+ unique_host_soname: true,
+ target: {
+ android_arm64: {
+ srcs: ["android/arm64/lib/mylib.so"],
+ },
+ android_arm: {
+ srcs: ["android/arm/lib/mylib.so"],
+ },
+ linux_glibc_x86_64: {
+ srcs: ["linux_glibc/x86_64/lib/mylib-host.so"],
+ },
+ linux_glibc_x86: {
+ srcs: ["linux_glibc/x86/lib/mylib-host.so"],
+ },
+ },
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ host_supported: true,
+ native_shared_libs: ["mysdk_mylib@current"],
+}
+`),
+ checkAllCopyRules(`
+.intermediates/mylib/android_arm64_armv8-a_shared/mylib.so -> android/arm64/lib/mylib.so
+.intermediates/mylib/android_arm_armv7-a-neon_shared/mylib.so -> android/arm/lib/mylib.so
+.intermediates/mylib/linux_glibc_x86_64_shared/mylib-host.so -> linux_glibc/x86_64/lib/mylib-host.so
+.intermediates/mylib/linux_glibc_x86_shared/mylib-host.so -> linux_glibc/x86/lib/mylib-host.so
+`),
+ )
+}
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 56706c7..77a4e94 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -34,6 +34,8 @@
"api/test-removed.txt": nil,
"api/module-lib-current.txt": nil,
"api/module-lib-removed.txt": nil,
+ "api/system-server-current.txt": nil,
+ "api/system-server-removed.txt": nil,
"build/soong/scripts/gen-java-current-api-files.sh": nil,
}
@@ -61,6 +63,9 @@
name: "android_module_lib_stubs_current",
}
java_import {
+ name: "android_system_server_stubs_current",
+}
+java_import {
name: "core-lambda-stubs",
sdk_version: "none",
}
@@ -1398,6 +1403,93 @@
)
}
+func TestSnapshotWithJavaSdkLibrary_SystemServer(t *testing.T) {
+ result := testSdkWithJava(t, `
+ sdk {
+ name: "mysdk",
+ java_sdk_libs: ["myjavalib"],
+ }
+
+ java_sdk_library {
+ name: "myjavalib",
+ apex_available: ["//apex_available:anyapex"],
+ srcs: ["Test.java"],
+ sdk_version: "current",
+ public: {
+ enabled: true,
+ },
+ system_server: {
+ enabled: true,
+ },
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_sdk_library_import {
+ name: "mysdk_myjavalib@current",
+ sdk_member_name: "myjavalib",
+ apex_available: ["//apex_available:anyapex"],
+ shared_library: true,
+ public: {
+ jars: ["sdk_library/public/myjavalib-stubs.jar"],
+ stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
+ current_api: "sdk_library/public/myjavalib.txt",
+ removed_api: "sdk_library/public/myjavalib-removed.txt",
+ sdk_version: "current",
+ },
+ system_server: {
+ jars: ["sdk_library/system-server/myjavalib-stubs.jar"],
+ stub_srcs: ["sdk_library/system-server/myjavalib_stub_sources"],
+ current_api: "sdk_library/system-server/myjavalib.txt",
+ removed_api: "sdk_library/system-server/myjavalib-removed.txt",
+ sdk_version: "system_server_current",
+ },
+}
+
+java_sdk_library_import {
+ name: "myjavalib",
+ prefer: false,
+ apex_available: ["//apex_available:anyapex"],
+ shared_library: true,
+ public: {
+ jars: ["sdk_library/public/myjavalib-stubs.jar"],
+ stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
+ current_api: "sdk_library/public/myjavalib.txt",
+ removed_api: "sdk_library/public/myjavalib-removed.txt",
+ sdk_version: "current",
+ },
+ system_server: {
+ jars: ["sdk_library/system-server/myjavalib-stubs.jar"],
+ stub_srcs: ["sdk_library/system-server/myjavalib_stub_sources"],
+ current_api: "sdk_library/system-server/myjavalib.txt",
+ removed_api: "sdk_library/system-server/myjavalib-removed.txt",
+ sdk_version: "system_server_current",
+ },
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ java_sdk_libs: ["mysdk_myjavalib@current"],
+}
+`),
+ checkAllCopyRules(`
+.intermediates/myjavalib.stubs/android_common/javac/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source/android_common/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
+.intermediates/myjavalib.stubs.source/android_common/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.system_server/android_common/javac/myjavalib.stubs.system_server.jar -> sdk_library/system-server/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source.system_server/android_common/myjavalib.stubs.source.system_server_api.txt -> sdk_library/system-server/myjavalib.txt
+.intermediates/myjavalib.stubs.source.system_server/android_common/myjavalib.stubs.source.system_server_removed.txt -> sdk_library/system-server/myjavalib-removed.txt
+`),
+ checkMergeZips(
+ ".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip",
+ ".intermediates/mysdk/common_os/tmp/sdk_library/system-server/myjavalib_stub_sources.zip",
+ ),
+ )
+}
+
func TestSnapshotWithJavaSdkLibrary_NamingScheme(t *testing.T) {
result := testSdkWithJava(t, `
sdk {
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index 7bb267d..f28b2b6 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -107,6 +107,8 @@
testProperties TestProperties
+ installDir android.InstallPath
+
data android.Paths
testConfig android.Path
}
@@ -176,13 +178,13 @@
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(entries *android.AndroidMkEntries) {
s.customAndroidMkEntries(entries)
+ entries.SetString("LOCAL_MODULE_RELATIVE_PATH", proptools.String(s.properties.Sub_dir))
},
},
}}
}
func (s *ShBinary) customAndroidMkEntries(entries *android.AndroidMkEntries) {
- entries.SetString("LOCAL_MODULE_RELATIVE_PATH", proptools.String(s.properties.Sub_dir))
entries.SetString("LOCAL_MODULE_SUFFIX", "")
entries.SetString("LOCAL_MODULE_STEM", s.outputFilePath.Rel())
if len(s.properties.Symlinks) > 0 {
@@ -201,8 +203,14 @@
} else if !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) {
testDir = filepath.Join(testDir, ctx.Arch().ArchType.String())
}
- installDir := android.PathForModuleInstall(ctx, testDir, proptools.String(s.properties.Sub_dir))
- s.installedFile = ctx.InstallExecutable(installDir, s.outputFilePath.Base(), s.outputFilePath)
+ if s.SubDir() != "" {
+ // Don't add the module name to the installation path if sub_dir is specified for backward
+ // compatibility.
+ s.installDir = android.PathForModuleInstall(ctx, testDir, s.SubDir())
+ } else {
+ s.installDir = android.PathForModuleInstall(ctx, testDir, s.Name())
+ }
+ s.installedFile = ctx.InstallExecutable(s.installDir, s.outputFilePath.Base(), s.outputFilePath)
s.data = android.PathsForModuleSrc(ctx, s.testProperties.Data)
@@ -229,7 +237,7 @@
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(entries *android.AndroidMkEntries) {
s.customAndroidMkEntries(entries)
-
+ entries.SetPath("LOCAL_MODULE_PATH", s.installDir.ToMakePath())
entries.AddStrings("LOCAL_COMPATIBILITY_SUITE", s.testProperties.Test_suites...)
if s.testConfig != nil {
entries.SetPath("LOCAL_FULL_TEST_CONFIG", s.testConfig)
diff --git a/sh/sh_binary_test.go b/sh/sh_binary_test.go
index 6c0d96a..3bfe611 100644
--- a/sh/sh_binary_test.go
+++ b/sh/sh_binary_test.go
@@ -55,7 +55,27 @@
return ctx, config
}
-func TestShTestTestData(t *testing.T) {
+func TestShTestSubDir(t *testing.T) {
+ ctx, config := testShBinary(t, `
+ sh_test {
+ name: "foo",
+ src: "test.sh",
+ sub_dir: "foo_test"
+ }
+ `)
+
+ mod := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*ShTest)
+
+ entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0]
+
+ expectedPath := "/tmp/target/product/test_device/data/nativetest64/foo_test"
+ actualPath := entries.EntryMap["LOCAL_MODULE_PATH"][0]
+ if expectedPath != actualPath {
+ t.Errorf("Unexpected LOCAL_MODULE_PATH expected: %q, actual: %q", expectedPath, actualPath)
+ }
+}
+
+func TestShTest(t *testing.T) {
ctx, config := testShBinary(t, `
sh_test {
name: "foo",
@@ -71,10 +91,17 @@
mod := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*ShTest)
entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0]
- expected := []string{":testdata/data1", ":testdata/sub/data2"}
- actual := entries.EntryMap["LOCAL_TEST_DATA"]
- if !reflect.DeepEqual(expected, actual) {
- t.Errorf("Unexpected test data expected: %q, actual: %q", expected, actual)
+
+ expectedPath := "/tmp/target/product/test_device/data/nativetest64/foo"
+ actualPath := entries.EntryMap["LOCAL_MODULE_PATH"][0]
+ if expectedPath != actualPath {
+ t.Errorf("Unexpected LOCAL_MODULE_PATH expected: %q, actual: %q", expectedPath, actualPath)
+ }
+
+ expectedData := []string{":testdata/data1", ":testdata/sub/data2"}
+ actualData := entries.EntryMap["LOCAL_TEST_DATA"]
+ if !reflect.DeepEqual(expectedData, actualData) {
+ t.Errorf("Unexpected test data expected: %q, actual: %q", expectedData, actualData)
}
}
diff --git a/ui/build/upload.go b/ui/build/upload.go
index 75a5e2f..3a23a80 100644
--- a/ui/build/upload.go
+++ b/ui/build/upload.go
@@ -23,6 +23,7 @@
"path/filepath"
"time"
+ "android/soong/ui/metrics"
"github.com/golang/protobuf/proto"
upload_proto "android/soong/ui/metrics/upload_proto"
@@ -32,11 +33,21 @@
uploadPbFilename = ".uploader.pb"
)
+var (
+ // For testing purpose
+ getTmpDir = ioutil.TempDir
+)
+
// UploadMetrics uploads a set of metrics files to a server for analysis. An
// uploader full path is required to be specified in order to upload the set
// of metrics files. This is accomplished by defining the ANDROID_ENABLE_METRICS_UPLOAD
-// environment variable.
-func UploadMetrics(ctx Context, config Config, buildStartedMilli int64, files ...string) {
+// environment variable. The metrics files are copied to a temporary directory
+// and the uploader is then executed in the background to allow the user to continue
+// working.
+func UploadMetrics(ctx Context, config Config, forceDumbOutput bool, buildStartedMilli int64, files ...string) {
+ ctx.BeginTrace(metrics.RunSetupTool, "upload_metrics")
+ defer ctx.EndTrace()
+
uploader := config.MetricsUploaderApp()
// No metrics to upload if the path to the uploader was not specified.
if uploader == "" {
@@ -56,6 +67,22 @@
return
}
+ // The temporary directory cannot be deleted as the metrics uploader is started
+ // in the background and requires to exist until the operation is done. The
+ // uploader can delete the directory as it is specified in the upload proto.
+ tmpDir, err := getTmpDir("", "upload_metrics")
+ if err != nil {
+ ctx.Fatalf("failed to create a temporary directory to store the list of metrics files: %v\n", err)
+ }
+
+ for i, src := range metricsFiles {
+ dst := filepath.Join(tmpDir, filepath.Base(src))
+ if _, err := copyFile(src, dst); err != nil {
+ ctx.Fatalf("failed to copy %q to %q: %v\n", src, dst, err)
+ }
+ metricsFiles[i] = dst
+ }
+
// For platform builds, the branch and target name is hardcoded to specific
// values for later extraction of the metrics in the data metrics pipeline.
data, err := proto.Marshal(&upload_proto.Upload{
@@ -64,17 +91,23 @@
BranchName: proto.String("developer-metrics"),
TargetName: proto.String("platform-build-systems-metrics"),
MetricsFiles: metricsFiles,
+ DirectoriesToDelete: []string{tmpDir},
})
if err != nil {
ctx.Fatalf("failed to marshal metrics upload proto buffer message: %v\n", err)
}
- pbFile := filepath.Join(config.OutDir(), uploadPbFilename)
+ pbFile := filepath.Join(tmpDir, uploadPbFilename)
if err := ioutil.WriteFile(pbFile, data, 0644); err != nil {
ctx.Fatalf("failed to write the marshaled metrics upload protobuf to %q: %v\n", pbFile, err)
}
- // Remove the upload file as it's not longer needed after it has been processed by the uploader.
- defer os.Remove(pbFile)
- Command(ctx, config, "upload metrics", uploader, "--upload-metrics", pbFile).RunAndStreamOrFatal()
+ // Start the uploader in the background as it takes several milliseconds to start the uploader
+ // and prepare the metrics for upload. This affects small commands like "lunch".
+ cmd := Command(ctx, config, "upload metrics", uploader, "--upload-metrics", pbFile)
+ if forceDumbOutput {
+ cmd.RunOrFatal()
+ } else {
+ cmd.RunAndStreamOrFatal()
+ }
}
diff --git a/ui/build/upload_test.go b/ui/build/upload_test.go
index adaa08d..c812730 100644
--- a/ui/build/upload_test.go
+++ b/ui/build/upload_test.go
@@ -15,6 +15,7 @@
package build
import (
+ "errors"
"io/ioutil"
"os"
"path/filepath"
@@ -61,6 +62,22 @@
}
defer os.RemoveAll(outDir)
+ // Supply our own getTmpDir to delete the temp dir once the test is done.
+ orgGetTmpDir := getTmpDir
+ getTmpDir = func(string, string) (string, error) {
+ retDir := filepath.Join(outDir, "tmp_upload_dir")
+ if err := os.Mkdir(retDir, 0755); err != nil {
+ t.Fatalf("failed to create temporary directory %q: %v", retDir, err)
+ }
+ return retDir, nil
+ }
+ defer func() { getTmpDir = orgGetTmpDir }()
+
+ metricsUploadDir := filepath.Join(outDir, ".metrics_uploader")
+ if err := os.Mkdir(metricsUploadDir, 0755); err != nil {
+ t.Fatalf("failed to create %q directory for oauth valid check: %v", metricsUploadDir, err)
+ }
+
var metricsFiles []string
if tt.createFiles {
for _, f := range tt.files {
@@ -80,41 +97,62 @@
buildDateTime: strconv.FormatInt(time.Now().UnixNano()/int64(time.Millisecond), 10),
}}
- UploadMetrics(ctx, config, 1591031903, metricsFiles...)
-
- if _, err := os.Stat(filepath.Join(outDir, uploadPbFilename)); err == nil {
- t.Error("got true, want false for upload protobuf file to exist")
- }
+ UploadMetrics(ctx, config, false, 1591031903, metricsFiles...)
})
}
}
func TestUploadMetricsErrors(t *testing.T) {
- expectedErr := "failed to write the marshaled"
- defer logger.Recover(func(err error) {
- got := err.Error()
- if !strings.Contains(got, expectedErr) {
- t.Errorf("got %q, want %q to be contained in error", got, expectedErr)
- }
- })
+ ctx := testContext()
+ tests := []struct {
+ description string
+ tmpDir string
+ tmpDirErr error
+ expectedErr string
+ }{{
+ description: "getTmpDir returned error",
+ tmpDirErr: errors.New("getTmpDir failed"),
+ expectedErr: "getTmpDir failed",
+ }, {
+ description: "copyFile operation error",
+ tmpDir: "/fake_dir",
+ expectedErr: "failed to copy",
+ }}
- outDir, err := ioutil.TempDir("", "")
- if err != nil {
- t.Fatalf("failed to create out directory: %v", outDir)
+ for _, tt := range tests {
+ t.Run(tt.description, func(t *testing.T) {
+ defer logger.Recover(func(err error) {
+ got := err.Error()
+ if !strings.Contains(got, tt.expectedErr) {
+ t.Errorf("got %q, want %q to be contained in error", got, tt.expectedErr)
+ }
+ })
+
+ outDir, err := ioutil.TempDir("", "")
+ if err != nil {
+ t.Fatalf("failed to create out directory: %v", outDir)
+ }
+ defer os.RemoveAll(outDir)
+
+ orgGetTmpDir := getTmpDir
+ getTmpDir = func(string, string) (string, error) {
+ return tt.tmpDir, tt.tmpDirErr
+ }
+ defer func() { getTmpDir = orgGetTmpDir }()
+
+ metricsFile := filepath.Join(outDir, "metrics_file_1")
+ if err := ioutil.WriteFile(metricsFile, []byte("test file"), 0644); err != nil {
+ t.Fatalf("failed to create a fake metrics file %q for uploading: %v", metricsFile, err)
+ }
+
+ config := Config{&configImpl{
+ environ: &Environment{
+ "ANDROID_ENABLE_METRICS_UPLOAD=fake",
+ "OUT_DIR=/bad",
+ }}}
+
+ UploadMetrics(ctx, config, true, 1591031903, metricsFile)
+ t.Errorf("got nil, expecting %q as a failure", tt.expectedErr)
+ })
}
- defer os.RemoveAll(outDir)
-
- metricsFile := filepath.Join(outDir, "metrics_file_1")
- if err := ioutil.WriteFile(metricsFile, []byte("test file"), 0644); err != nil {
- t.Fatalf("failed to create a fake metrics file %q for uploading: %v", metricsFile, err)
- }
-
- config := Config{&configImpl{
- environ: &Environment{
- "ANDROID_ENABLE_METRICS_UPLOAD=fake",
- "OUT_DIR=/bad",
- }}}
-
- UploadMetrics(testContext(), config, 1591031903, metricsFile)
- t.Errorf("got nil, expecting %q as a failure", expectedErr)
}
diff --git a/ui/build/util.go b/ui/build/util.go
index 75e6753..d44cd6d 100644
--- a/ui/build/util.go
+++ b/ui/build/util.go
@@ -15,6 +15,7 @@
package build
import (
+ "io"
"os"
"path/filepath"
"strings"
@@ -124,3 +125,20 @@
}
return str[:idx], str[idx+1:], true
}
+
+// copyFile copies a file from src to dst. filepath.Dir(dst) must exist.
+func copyFile(src, dst string) (int64, error) {
+ source, err := os.Open(src)
+ if err != nil {
+ return 0, err
+ }
+ defer source.Close()
+
+ destination, err := os.Create(dst)
+ if err != nil {
+ return 0, err
+ }
+ defer destination.Close()
+
+ return io.Copy(destination, source)
+}
diff --git a/ui/build/util_test.go b/ui/build/util_test.go
index 89bfc77..b22e997 100644
--- a/ui/build/util_test.go
+++ b/ui/build/util_test.go
@@ -15,6 +15,7 @@
package build
import (
+ "bytes"
"io/ioutil"
"os"
"path/filepath"
@@ -49,3 +50,72 @@
ensureEmptyDirectoriesExist(ctx, filepath.Join(tmpDir, "a"))
}
+
+func TestCopyFile(t *testing.T) {
+ tmpDir, err := ioutil.TempDir("", "test_copy_file")
+ if err != nil {
+ t.Fatalf("failed to create temporary directory to hold test text files: %v", err)
+ }
+ defer os.Remove(tmpDir)
+
+ data := []byte("fake data")
+ src := filepath.Join(tmpDir, "src.txt")
+ if err := ioutil.WriteFile(src, data, 0755); err != nil {
+ t.Fatalf("failed to create a src file %q for copying: %v", src, err)
+ }
+
+ dst := filepath.Join(tmpDir, "dst.txt")
+
+ l, err := copyFile(src, dst)
+ if err != nil {
+ t.Fatalf("got %v, expecting nil error on copyFile operation", err)
+ }
+
+ if l != int64(len(data)) {
+ t.Errorf("got %d, expecting %d for copied bytes", l, len(data))
+ }
+
+ dstData, err := ioutil.ReadFile(dst)
+ if err != nil {
+ t.Fatalf("got %v, expecting nil error reading dst %q file", err, dst)
+ }
+
+ if bytes.Compare(data, dstData) != 0 {
+ t.Errorf("got %q, expecting data %q from dst %q text file", string(data), string(dstData), dst)
+ }
+}
+
+func TestCopyFileErrors(t *testing.T) {
+ tmpDir, err := ioutil.TempDir("", "test_copy_file_errors")
+ if err != nil {
+ t.Fatalf("failed to create temporary directory to hold test text files: %v", err)
+ }
+ defer os.Remove(tmpDir)
+
+ srcExists := filepath.Join(tmpDir, "src_exist.txt")
+ if err := ioutil.WriteFile(srcExists, []byte("fake data"), 0755); err != nil {
+ t.Fatalf("failed to create a src file %q for copying: %v", srcExists, err)
+ }
+
+ tests := []struct {
+ description string
+ src string
+ dst string
+ }{{
+ description: "src file does not exist",
+ src: "/src/not/exist",
+ dst: "/dst/not/exist",
+ }, {
+ description: "dst directory does not exist",
+ src: srcExists,
+ dst: "/dst/not/exist",
+ }}
+
+ for _, tt := range tests {
+ t.Run(tt.description, func(t *testing.T) {
+ if _, err := copyFile(tt.src, tt.dst); err == nil {
+ t.Errorf("got nil, expecting error")
+ }
+ })
+ }
+}
diff --git a/ui/metrics/upload_proto/upload.pb.go b/ui/metrics/upload_proto/upload.pb.go
index 1b1e5e8..614d4c7 100644
--- a/ui/metrics/upload_proto/upload.pb.go
+++ b/ui/metrics/upload_proto/upload.pb.go
@@ -30,7 +30,10 @@
// The target name.
TargetName *string `protobuf:"bytes,4,opt,name=target_name,json=targetName" json:"target_name,omitempty"`
// A list of metrics filepaths to upload.
- MetricsFiles []string `protobuf:"bytes,5,rep,name=metrics_files,json=metricsFiles" json:"metrics_files,omitempty"`
+ MetricsFiles []string `protobuf:"bytes,5,rep,name=metrics_files,json=metricsFiles" json:"metrics_files,omitempty"`
+ // A list of directories to delete after the copy of metrics files
+ // is completed for uploading.
+ DirectoriesToDelete []string `protobuf:"bytes,6,rep,name=directories_to_delete,json=directoriesToDelete" json:"directories_to_delete,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@@ -96,6 +99,13 @@
return nil
}
+func (m *Upload) GetDirectoriesToDelete() []string {
+ if m != nil {
+ return m.DirectoriesToDelete
+ }
+ return nil
+}
+
func init() {
proto.RegisterType((*Upload)(nil), "soong_metrics_upload.Upload")
}
@@ -105,18 +115,20 @@
}
var fileDescriptor_91b94b655bd2a7e5 = []byte{
- // 201 bytes of a gzipped FileDescriptorProto
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x29, 0x2d, 0xc8, 0xc9,
- 0x4f, 0x4c, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x29, 0xce, 0xcf, 0xcf, 0x4b, 0x8f,
- 0xcf, 0x4d, 0x2d, 0x29, 0xca, 0x4c, 0x2e, 0x8e, 0x87, 0xc8, 0x29, 0xdd, 0x66, 0xe4, 0x62, 0x0b,
- 0x05, 0x33, 0x85, 0x8c, 0xb8, 0x44, 0x93, 0x8b, 0x52, 0x13, 0x4b, 0x32, 0xf3, 0xf3, 0xe2, 0x4b,
- 0x32, 0x73, 0x53, 0x8b, 0x4b, 0x12, 0x73, 0x0b, 0xe2, 0x73, 0x8b, 0x25, 0x18, 0x15, 0x18, 0x35,
- 0x58, 0x82, 0x84, 0x61, 0x92, 0x21, 0x30, 0x39, 0xdf, 0x62, 0x21, 0x33, 0x2e, 0xf1, 0xe4, 0xfc,
- 0xdc, 0x82, 0x9c, 0x54, 0x4c, 0x5d, 0x4c, 0x60, 0x5d, 0xa2, 0x08, 0x69, 0x64, 0x7d, 0xf2, 0x5c,
- 0xdc, 0x49, 0x45, 0x89, 0x79, 0xc9, 0x19, 0xf1, 0x79, 0x89, 0xb9, 0xa9, 0x12, 0xcc, 0x0a, 0x8c,
- 0x1a, 0x9c, 0x41, 0x5c, 0x10, 0x21, 0xbf, 0xc4, 0xdc, 0x54, 0x90, 0x82, 0x92, 0xc4, 0xa2, 0xf4,
- 0xd4, 0x12, 0x88, 0x02, 0x16, 0x88, 0x02, 0x88, 0x10, 0x58, 0x81, 0x32, 0x17, 0x2f, 0xcc, 0x2b,
- 0x69, 0x99, 0x39, 0xa9, 0xc5, 0x12, 0xac, 0x0a, 0xcc, 0x1a, 0x9c, 0x41, 0x3c, 0x50, 0x41, 0x37,
- 0x90, 0x98, 0x93, 0x4c, 0x94, 0x14, 0x36, 0x5f, 0xc7, 0x83, 0x43, 0x04, 0x10, 0x00, 0x00, 0xff,
- 0xff, 0xe2, 0x01, 0x74, 0x65, 0x20, 0x01, 0x00, 0x00,
+ // 230 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x90, 0xb1, 0x4a, 0x04, 0x31,
+ 0x10, 0x86, 0xd9, 0xbb, 0xf3, 0xe0, 0xe2, 0xd9, 0xec, 0x79, 0x18, 0x44, 0x70, 0xd1, 0x66, 0x2b,
+ 0x0b, 0x0b, 0x1f, 0x40, 0xc4, 0x4e, 0x8b, 0xe5, 0x6c, 0x6c, 0x86, 0x98, 0x1d, 0xd7, 0x40, 0x92,
+ 0x09, 0xc9, 0xf8, 0x1c, 0xbe, 0xb2, 0x6c, 0xe2, 0xe2, 0x82, 0x76, 0xc3, 0xff, 0x7d, 0x7f, 0x31,
+ 0xbf, 0xd8, 0x7e, 0x06, 0x4b, 0xaa, 0xbf, 0x09, 0x91, 0x98, 0xea, 0xd3, 0x44, 0xe4, 0x07, 0x70,
+ 0xc8, 0xd1, 0xe8, 0x04, 0x85, 0x5d, 0x7d, 0x2d, 0xc4, 0xfa, 0x25, 0x9f, 0xf5, 0xad, 0xd8, 0xeb,
+ 0x88, 0x8a, 0x0d, 0x79, 0x60, 0xe3, 0x30, 0xb1, 0x72, 0x01, 0x5c, 0x92, 0x55, 0x53, 0xb5, 0xab,
+ 0x6e, 0x37, 0xc1, 0xc3, 0xc4, 0x9e, 0x52, 0x7d, 0x27, 0xce, 0x34, 0xb9, 0x60, 0xf1, 0x6f, 0x6b,
+ 0x91, 0x5b, 0xfb, 0x5f, 0x3c, 0xef, 0x5d, 0x8a, 0xe3, 0xb7, 0xa8, 0xbc, 0xfe, 0x00, 0xaf, 0x1c,
+ 0xca, 0x65, 0x53, 0xb5, 0x9b, 0x4e, 0x94, 0xe8, 0x59, 0x39, 0x1c, 0x05, 0x56, 0x71, 0x40, 0x2e,
+ 0xc2, 0xaa, 0x08, 0x25, 0xca, 0xc2, 0xb5, 0x38, 0x99, 0x5e, 0x79, 0x37, 0x16, 0x93, 0x3c, 0x6a,
+ 0x96, 0xed, 0xa6, 0xdb, 0xfe, 0x84, 0x8f, 0x63, 0x36, 0xbe, 0xd4, 0x9b, 0x88, 0x9a, 0x29, 0x1a,
+ 0x4c, 0xc0, 0x04, 0x3d, 0x5a, 0x64, 0x94, 0xeb, 0x2c, 0xef, 0x66, 0xf0, 0x40, 0x0f, 0x19, 0xdd,
+ 0x5f, 0xbc, 0x9e, 0xff, 0xb7, 0x14, 0xe4, 0x15, 0xbf, 0x03, 0x00, 0x00, 0xff, 0xff, 0x64, 0x04,
+ 0xa8, 0xf4, 0x54, 0x01, 0x00, 0x00,
}
diff --git a/ui/metrics/upload_proto/upload.proto b/ui/metrics/upload_proto/upload.proto
index 7a9f080..bcd0ab2 100644
--- a/ui/metrics/upload_proto/upload.proto
+++ b/ui/metrics/upload_proto/upload.proto
@@ -32,4 +32,8 @@
// A list of metrics filepaths to upload.
repeated string metrics_files = 5;
+
+ // A list of directories to delete after the copy of metrics files
+ // is completed for uploading.
+ repeated string directories_to_delete = 6;
}