diff options
63 files changed, 1132 insertions, 347 deletions
@@ -11,3 +11,4 @@ per-file clang.go,global.go = srhines@google.com, chh@google.com, pirama@google. per-file tidy.go = srhines@google.com, chh@google.com per-file lto.go,pgo.go = srhines@google.com, pirama@google.com, yikong@google.com per-file docs/map_files.md = danalbert@google.com, enh@google.com, jiyong@google.com +per-file *ndk_api_coverage_parser.py = sophiez@google.com
\ No newline at end of file diff --git a/android/Android.bp b/android/Android.bp index 47dbc5d5f..487372bd8 100644 --- a/android/Android.bp +++ b/android/Android.bp @@ -36,6 +36,7 @@ bootstrap_go_package { "package_ctx.go", "path_properties.go", "paths.go", + "phony.go", "prebuilt.go", "proto.go", "register.go", diff --git a/android/arch.go b/android/arch.go index 08c0256b7..9a5461474 100644 --- a/android/arch.go +++ b/android/arch.go @@ -810,7 +810,7 @@ func GetOsSpecificVariantsOfCommonOSVariant(mctx BaseModuleContext) []Module { // Valid multilib values include: // "both": compile for all Targets supported by the OsClass (generally x86_64 and x86, or arm64 and arm). // "first": compile for only a single preferred Target supported by the OsClass. This is generally x86_64 or arm64, -// but may be arm for a 32-bit only build or a build with TARGET_PREFER_32_BIT=true set. +// but may be arm for a 32-bit only build. // "32": compile for only a single 32-bit Target supported by the OsClass. // "64": compile for only a single 64-bit Target supported by the OsClass. // "common": compile a for a single Target that will work on all Targets suported by the OsClass (for example Java). @@ -1026,6 +1026,7 @@ func createArchPropTypeDesc(props reflect.Type) []archPropTypeDesc { "Not_windows", "Arm_on_x86", "Arm_on_x86_64", + "Native_bridge", } for _, os := range OsTypeList { targets = append(targets, os.Field) @@ -1413,6 +1414,11 @@ func (m *ModuleBase) setArchProperties(ctx BottomUpMutatorContext) { prefix := "target.arm_on_x86_64" m.appendProperties(ctx, genProps, targetProp, field, prefix) } + if os == Android && m.Target().NativeBridge == NativeBridgeEnabled { + field := "Native_bridge" + prefix := "target.native_bridge" + m.appendProperties(ctx, genProps, targetProp, field, prefix) + } } } } diff --git a/android/arch_test.go b/android/arch_test.go index b987d5697..8525b0349 100644 --- a/android/arch_test.go +++ b/android/arch_test.go @@ -383,3 +383,88 @@ func TestArchMutator(t *testing.T) { }) } } + +func TestArchMutatorNativeBridge(t *testing.T) { + bp := ` + // This module is only enabled for x86. + module { + name: "foo", + } + + // This module is enabled for x86 and arm (via native bridge). + module { + name: "bar", + native_bridge_supported: true, + } + + // This module is enabled for arm (native_bridge) only. + module { + name: "baz", + native_bridge_supported: true, + enabled: false, + target: { + native_bridge: { + enabled: true, + } + } + } + ` + + testCases := []struct { + name string + config func(Config) + fooVariants []string + barVariants []string + bazVariants []string + }{ + { + name: "normal", + config: nil, + fooVariants: []string{"android_x86_64_silvermont", "android_x86_silvermont"}, + barVariants: []string{"android_x86_64_silvermont", "android_native_bridge_arm64_armv8-a", "android_x86_silvermont", "android_native_bridge_arm_armv7-a-neon"}, + bazVariants: []string{"android_native_bridge_arm64_armv8-a", "android_native_bridge_arm_armv7-a-neon"}, + }, + } + + enabledVariants := func(ctx *TestContext, name string) []string { + var ret []string + variants := ctx.ModuleVariantsForTests(name) + for _, variant := range variants { + m := ctx.ModuleForTests(name, variant) + if m.Module().Enabled() { + ret = append(ret, variant) + } + } + return ret + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + config := TestArchConfigNativeBridge(buildDir, nil, bp, nil) + + ctx := NewTestArchContext() + ctx.RegisterModuleType("module", archTestModuleFactory) + ctx.Register(config) + if tt.config != nil { + tt.config(config) + } + + _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) + FailIfErrored(t, errs) + _, errs = ctx.PrepareBuildActions(config) + FailIfErrored(t, errs) + + if g, w := enabledVariants(ctx, "foo"), tt.fooVariants; !reflect.DeepEqual(w, g) { + t.Errorf("want foo variants:\n%q\ngot:\n%q\n", w, g) + } + + if g, w := enabledVariants(ctx, "bar"), tt.barVariants; !reflect.DeepEqual(w, g) { + t.Errorf("want bar variants:\n%q\ngot:\n%q\n", w, g) + } + + if g, w := enabledVariants(ctx, "baz"), tt.bazVariants; !reflect.DeepEqual(w, g) { + t.Errorf("want qux variants:\n%q\ngot:\n%q\n", w, g) + } + }) + } +} diff --git a/android/config.go b/android/config.go index 59118ce86..0fe4a0c68 100644 --- a/android/config.go +++ b/android/config.go @@ -111,6 +111,10 @@ type config struct { fs pathtools.FileSystem mockBpList string + // If testAllowNonExistentPaths is true then PathForSource and PathForModuleSrc won't error + // in tests when a path doesn't exist. + testAllowNonExistentPaths bool + OncePer } @@ -230,6 +234,10 @@ func TestConfig(buildDir string, env map[string]string, bp string, fs map[string buildDir: buildDir, captureBuild: true, env: envCopy, + + // Set testAllowNonExistentPaths so that test contexts don't need to specify every path + // passed to PathForSource or PathForModuleSrc. + testAllowNonExistentPaths: true, } config.deviceConfig = &deviceConfig{ config: config, @@ -732,14 +740,6 @@ func (c *config) Eng() bool { return Bool(c.productVariables.Eng) } -func (c *config) DevicePrefer32BitApps() bool { - return Bool(c.productVariables.DevicePrefer32BitApps) -} - -func (c *config) DevicePrefer32BitExecutables() bool { - return Bool(c.productVariables.DevicePrefer32BitExecutables) -} - func (c *config) DevicePrimaryArchType() ArchType { return c.Targets[Android][0].Arch.ArchType } @@ -1163,8 +1163,8 @@ func (c *config) EnforceSystemCertificate() bool { return Bool(c.productVariables.EnforceSystemCertificate) } -func (c *config) EnforceSystemCertificateWhitelist() []string { - return c.productVariables.EnforceSystemCertificateWhitelist +func (c *config) EnforceSystemCertificateAllowList() []string { + return c.productVariables.EnforceSystemCertificateAllowList } func (c *config) EnforceProductPartitionInterface() bool { diff --git a/android/makevars.go b/android/makevars.go index aba4ccec3..ff7c8e4a7 100644 --- a/android/makevars.go +++ b/android/makevars.go @@ -17,12 +17,11 @@ package android import ( "bytes" "fmt" - "io/ioutil" - "os" "strconv" "strings" "github.com/google/blueprint" + "github.com/google/blueprint/pathtools" "github.com/google/blueprint/proptools" ) @@ -84,6 +83,29 @@ type MakeVarsContext interface { // builder whenever a file matching the pattern as added or removed, without rerunning if a // file that does not match the pattern is added to a searched directory. GlobWithDeps(pattern string, excludes []string) ([]string, error) + + // Phony creates a phony rule in Make, which will allow additional DistForGoal + // dependencies to be added to it. Phony can be called on the same name multiple + // times to add additional dependencies. + Phony(names string, deps ...Path) + + // DistForGoal creates a rule to copy one or more Paths to the artifacts + // directory on the build server when the specified goal is built. + DistForGoal(goal string, paths ...Path) + + // DistForGoalWithFilename creates a rule to copy a Path to the artifacts + // directory on the build server with the given filename when the specified + // goal is built. + DistForGoalWithFilename(goal string, path Path, filename string) + + // DistForGoals creates a rule to copy one or more Paths to the artifacts + // directory on the build server when any of the specified goals are built. + DistForGoals(goals []string, paths ...Path) + + // DistForGoalsWithFilename creates a rule to copy a Path to the artifacts + // directory on the build server with the given filename when any of the + // specified goals are built. + DistForGoalsWithFilename(goals []string, path Path, filename string) } var _ PathContext = MakeVarsContext(nil) @@ -130,9 +152,11 @@ var makeVarsProviders []makeVarsProvider type makeVarsContext struct { SingletonContext - config Config - pctx PackageContext - vars []makeVarsVariable + config Config + pctx PackageContext + vars []makeVarsVariable + phonies []phony + dists []dist } var _ MakeVarsContext = &makeVarsContext{} @@ -144,6 +168,16 @@ type makeVarsVariable struct { strict bool } +type phony struct { + name string + deps []string +} + +type dist struct { + goals []string + paths []string +} + func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) { if !ctx.Config().EmbeddedInMake() { return @@ -152,11 +186,16 @@ func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) { outFile := absolutePath(PathForOutput(ctx, "make_vars"+proptools.String(ctx.Config().productVariables.Make_suffix)+".mk").String()) + lateOutFile := absolutePath(PathForOutput(ctx, + "late"+proptools.String(ctx.Config().productVariables.Make_suffix)+".mk").String()) + if ctx.Failed() { return } - vars := []makeVarsVariable{} + var vars []makeVarsVariable + var dists []dist + var phonies []phony for _, provider := range makeVarsProviders { mctx := &makeVarsContext{ SingletonContext: ctx, @@ -166,6 +205,8 @@ func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) { provider.call(mctx) vars = append(vars, mctx.vars...) + phonies = append(phonies, mctx.phonies...) + dists = append(dists, mctx.dists...) } if ctx.Failed() { @@ -174,17 +215,16 @@ func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) { outBytes := s.writeVars(vars) - if _, err := os.Stat(absolutePath(outFile)); err == nil { - if data, err := ioutil.ReadFile(absolutePath(outFile)); err == nil { - if bytes.Equal(data, outBytes) { - return - } - } + if err := pathtools.WriteFileIfChanged(outFile, outBytes, 0666); err != nil { + ctx.Errorf(err.Error()) } - if err := ioutil.WriteFile(absolutePath(outFile), outBytes, 0666); err != nil { + lateOutBytes := s.writeLate(phonies, dists) + + if err := pathtools.WriteFileIfChanged(lateOutFile, lateOutBytes, 0666); err != nil { ctx.Errorf(err.Error()) } + } func (s *makeVarsSingleton) writeVars(vars []makeVarsVariable) []byte { @@ -263,6 +303,33 @@ my_check_failed := fmt.Fprintln(buf, "\nsoong-compare-var :=") + fmt.Fprintln(buf) + + return buf.Bytes() +} + +func (s *makeVarsSingleton) writeLate(phonies []phony, dists []dist) []byte { + buf := &bytes.Buffer{} + + fmt.Fprint(buf, `# Autogenerated file + +# Values written by Soong read after parsing all Android.mk files. + + +`) + + for _, phony := range phonies { + fmt.Fprintf(buf, ".PHONY: %s\n", phony.name) + fmt.Fprintf(buf, "%s: %s\n", phony.name, strings.Join(phony.deps, "\\\n ")) + } + + fmt.Fprintln(buf) + + for _, dist := range dists { + fmt.Fprintf(buf, "$(call dist-for-goals,%s,%s)\n", + strings.Join(dist.goals, " "), strings.Join(dist.paths, " ")) + } + return buf.Bytes() } @@ -299,6 +366,17 @@ func (c *makeVarsContext) addVariable(name, ninjaStr string, strict, sort bool) c.addVariableRaw(name, value, strict, sort) } +func (c *makeVarsContext) addPhony(name string, deps []string) { + c.phonies = append(c.phonies, phony{name, deps}) +} + +func (c *makeVarsContext) addDist(goals []string, paths []string) { + c.dists = append(c.dists, dist{ + goals: goals, + paths: paths, + }) +} + func (c *makeVarsContext) Strict(name, ninjaStr string) { c.addVariable(name, ninjaStr, true, false) } @@ -318,3 +396,23 @@ func (c *makeVarsContext) CheckSorted(name, ninjaStr string) { func (c *makeVarsContext) CheckRaw(name, value string) { c.addVariableRaw(name, value, false, false) } + +func (c *makeVarsContext) Phony(name string, deps ...Path) { + c.addPhony(name, Paths(deps).Strings()) +} + +func (c *makeVarsContext) DistForGoal(goal string, paths ...Path) { + c.DistForGoals([]string{goal}, paths...) +} + +func (c *makeVarsContext) DistForGoalWithFilename(goal string, path Path, filename string) { + c.DistForGoalsWithFilename([]string{goal}, path, filename) +} + +func (c *makeVarsContext) DistForGoals(goals []string, paths ...Path) { + c.addDist(goals, Paths(paths).Strings()) +} + +func (c *makeVarsContext) DistForGoalsWithFilename(goals []string, path Path, filename string) { + c.addDist(goals, []string{path.String() + ":" + filename}) +} diff --git a/android/module.go b/android/module.go index 82321f417..a488c0d77 100644 --- a/android/module.go +++ b/android/module.go @@ -207,6 +207,10 @@ type ModuleContext interface { // Similar to blueprint.ModuleContext.Build, but takes Paths instead of []string, // and performs more verification. Build(pctx PackageContext, params BuildParams) + // Phony creates a Make-style phony rule, a rule with no commands that can depend on other + // phony rules or real files. Phony can be called on the same name multiple times to add + // additional dependencies. + Phony(phony string, deps ...Path) PrimaryModule() Module FinalModule() Module @@ -722,6 +726,7 @@ type ModuleBase struct { installFiles InstallPaths checkbuildFiles Paths noticeFiles Paths + phonies map[string]Paths // Used by buildTargetSingleton to create checkbuild and per-directory build targets // Only set on the final variant of each module @@ -1093,26 +1098,17 @@ func (m *ModuleBase) generateModuleTarget(ctx ModuleContext) { } if len(allInstalledFiles) > 0 { - name := PathForPhony(ctx, namespacePrefix+ctx.ModuleName()+"-install") - ctx.Build(pctx, BuildParams{ - Rule: blueprint.Phony, - Output: name, - Implicits: allInstalledFiles.Paths(), - Default: !ctx.Config().EmbeddedInMake(), - }) - deps = append(deps, name) - m.installTarget = name + name := namespacePrefix + ctx.ModuleName() + "-install" + ctx.Phony(name, allInstalledFiles.Paths()...) + m.installTarget = PathForPhony(ctx, name) + deps = append(deps, m.installTarget) } if len(allCheckbuildFiles) > 0 { - name := PathForPhony(ctx, namespacePrefix+ctx.ModuleName()+"-checkbuild") - ctx.Build(pctx, BuildParams{ - Rule: blueprint.Phony, - Output: name, - Implicits: allCheckbuildFiles, - }) - deps = append(deps, name) - m.checkbuildTarget = name + name := namespacePrefix + ctx.ModuleName() + "-checkbuild" + ctx.Phony(name, allCheckbuildFiles...) + m.checkbuildTarget = PathForPhony(ctx, name) + deps = append(deps, m.checkbuildTarget) } if len(deps) > 0 { @@ -1121,12 +1117,7 @@ func (m *ModuleBase) generateModuleTarget(ctx ModuleContext) { suffix = "-soong" } - name := PathForPhony(ctx, namespacePrefix+ctx.ModuleName()+suffix) - ctx.Build(pctx, BuildParams{ - Rule: blueprint.Phony, - Outputs: []WritablePath{name}, - Implicits: deps, - }) + ctx.Phony(namespacePrefix+ctx.ModuleName()+suffix, deps...) m.blueprintDir = ctx.ModuleDir() } @@ -1313,6 +1304,9 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) m.checkbuildFiles = append(m.checkbuildFiles, ctx.checkbuildFiles...) m.initRcPaths = PathsForModuleSrc(ctx, m.commonProperties.Init_rc) m.vintfFragmentsPaths = PathsForModuleSrc(ctx, m.commonProperties.Vintf_fragments) + for k, v := range ctx.phonies { + m.phonies[k] = append(m.phonies[k], v...) + } } else if ctx.Config().AllowMissingDependencies() { // If the module is not enabled it will not create any build rules, nothing will call // ctx.GetMissingDependencies(), and blueprint will consider the missing dependencies to be unhandled @@ -1460,6 +1454,7 @@ type moduleContext struct { installFiles InstallPaths checkbuildFiles Paths module Module + phonies map[string]Paths // For tests buildParams []BuildParams @@ -1574,6 +1569,11 @@ func (m *moduleContext) Build(pctx PackageContext, params BuildParams) { m.bp.Build(pctx.PackageContext, convertBuildParams(params)) } + +func (m *moduleContext) Phony(name string, deps ...Path) { + addPhony(m.config, name, deps...) +} + func (m *moduleContext) GetMissingDependencies() []string { var missingDeps []string missingDeps = append(missingDeps, m.Module().base().commonProperties.MissingDeps...) @@ -2233,9 +2233,8 @@ type buildTargetSingleton struct{} func (c *buildTargetSingleton) GenerateBuildActions(ctx SingletonContext) { var checkbuildDeps Paths - mmTarget := func(dir string) WritablePath { - return PathForPhony(ctx, - "MODULES-IN-"+strings.Replace(filepath.Clean(dir), "/", "-", -1)) + mmTarget := func(dir string) string { + return "MODULES-IN-" + strings.Replace(filepath.Clean(dir), "/", "-", -1) } modulesInDir := make(map[string]Paths) @@ -2261,11 +2260,7 @@ func (c *buildTargetSingleton) GenerateBuildActions(ctx SingletonContext) { } // Create a top-level checkbuild target that depends on all modules - ctx.Build(pctx, BuildParams{ - Rule: blueprint.Phony, - Output: PathForPhony(ctx, "checkbuild"+suffix), - Implicits: checkbuildDeps, - }) + ctx.Phony("checkbuild"+suffix, checkbuildDeps...) // Make will generate the MODULES-IN-* targets if ctx.Config().EmbeddedInMake() { @@ -2289,7 +2284,7 @@ func (c *buildTargetSingleton) GenerateBuildActions(ctx SingletonContext) { for _, dir := range dirs { p := parentDir(dir) if p != "." && p != "/" { - modulesInDir[p] = append(modulesInDir[p], mmTarget(dir)) + modulesInDir[p] = append(modulesInDir[p], PathForPhony(ctx, mmTarget(dir))) } } @@ -2297,14 +2292,7 @@ func (c *buildTargetSingleton) GenerateBuildActions(ctx SingletonContext) { // depends on the MODULES-IN-* targets of all of its subdirectories that contain Android.bp // files. for _, dir := range dirs { - ctx.Build(pctx, BuildParams{ - Rule: blueprint.Phony, - Output: mmTarget(dir), - Implicits: modulesInDir[dir], - // HACK: checkbuild should be an optional build, but force it - // enabled for now in standalone builds - Default: !ctx.Config().EmbeddedInMake(), - }) + ctx.Phony(mmTarget(dir), modulesInDir[dir]...) } // Create (host|host-cross|target)-<OS> phony rules to build a reduced checkbuild. @@ -2331,23 +2319,15 @@ func (c *buildTargetSingleton) GenerateBuildActions(ctx SingletonContext) { continue } - name := PathForPhony(ctx, className+"-"+os.Name) - osClass[className] = append(osClass[className], name) + name := className + "-" + os.Name + osClass[className] = append(osClass[className], PathForPhony(ctx, name)) - ctx.Build(pctx, BuildParams{ - Rule: blueprint.Phony, - Output: name, - Implicits: deps, - }) + ctx.Phony(name, deps...) } // Wrap those into host|host-cross|target phony rules for _, class := range SortedStringKeys(osClass) { - ctx.Build(pctx, BuildParams{ - Rule: blueprint.Phony, - Output: PathForPhony(ctx, class), - Implicits: osClass[class], - }) + ctx.Phony(class, osClass[class]...) } } diff --git a/android/neverallow.go b/android/neverallow.go index be3f7123b..26e42e656 100644 --- a/android/neverallow.go +++ b/android/neverallow.go @@ -166,7 +166,7 @@ func createMediaRules() []Rule { } func createJavaDeviceForHostRules() []Rule { - javaDeviceForHostProjectsWhitelist := []string{ + javaDeviceForHostProjectsAllowedList := []string{ "external/guava", "external/robolectric-shadows", "framework/layoutlib", @@ -174,14 +174,14 @@ func createJavaDeviceForHostRules() []Rule { return []Rule{ NeverAllow(). - NotIn(javaDeviceForHostProjectsWhitelist...). + NotIn(javaDeviceForHostProjectsAllowedList...). ModuleType("java_device_for_host", "java_host_for_device"). - Because("java_device_for_host can only be used in whitelisted projects"), + Because("java_device_for_host can only be used in allowed projects"), } } func createCcSdkVariantRules() []Rule { - sdkVersionOnlyWhitelist := []string{ + sdkVersionOnlyAllowedList := []string{ // derive_sdk_prefer32 has stem: "derive_sdk" which conflicts with the derive_sdk. // This sometimes works because the APEX modules that contain derive_sdk and // derive_sdk_prefer32 suppress the platform installation rules, but fails when @@ -193,7 +193,7 @@ func createCcSdkVariantRules() []Rule { "tools/test/graphicsbenchmark/functional_tests/java", } - platformVariantPropertiesWhitelist := []string{ + platformVariantPropertiesAllowedList := []string{ // android_native_app_glue and libRSSupport use native_window.h but target old // sdk versions (minimum and 9 respectively) where libnativewindow didn't exist, // so they can't add libnativewindow to shared_libs to get the header directory @@ -205,13 +205,13 @@ func createCcSdkVariantRules() []Rule { return []Rule{ NeverAllow(). - NotIn(sdkVersionOnlyWhitelist...). + NotIn(sdkVersionOnlyAllowedList...). WithMatcher("sdk_variant_only", isSetMatcherInstance). - Because("sdk_variant_only can only be used in whitelisted projects"), + Because("sdk_variant_only can only be used in allowed projects"), NeverAllow(). - NotIn(platformVariantPropertiesWhitelist...). + NotIn(platformVariantPropertiesAllowedList...). WithMatcher("platform.shared_libs", isSetMatcherInstance). - Because("platform variant properties can only be used in whitelisted projects"), + Because("platform variant properties can only be used in allowed projects"), } } diff --git a/android/neverallow_test.go b/android/neverallow_test.go index 85c8c5908..45d36a69b 100644 --- a/android/neverallow_test.go +++ b/android/neverallow_test.go @@ -212,7 +212,7 @@ var neverallowTests = []struct { }`), }, expectedErrors: []string{ - "java_device_for_host can only be used in whitelisted projects", + "java_device_for_host can only be used in allowed projects", }, }, // Libcore rule tests @@ -261,46 +261,46 @@ var neverallowTests = []struct { }, // CC sdk rule tests { - name: `"sdk_variant_only" outside whitelist`, + name: `"sdk_variant_only" outside allowed list`, fs: map[string][]byte{ "Android.bp": []byte(` cc_library { - name: "outside_whitelist", + name: "outside_allowed_list", sdk_version: "current", sdk_variant_only: true, }`), }, expectedErrors: []string{ - `module "outside_whitelist": violates neverallow`, + `module "outside_allowed_list": violates neverallow`, }, }, { - name: `"sdk_variant_only: false" outside whitelist`, + name: `"sdk_variant_only: false" outside allowed list`, fs: map[string][]byte{ "Android.bp": []byte(` cc_library { - name: "outside_whitelist", + name: "outside_allowed_list", sdk_version: "current", sdk_variant_only: false, }`), }, expectedErrors: []string{ - `module "outside_whitelist": violates neverallow`, + `module "outside_allowed_list": violates neverallow`, }, }, { - name: `"platform" outside whitelist`, + name: `"platform" outside allowed list`, fs: map[string][]byte{ "Android.bp": []byte(` cc_library { - name: "outside_whitelist", + name: "outside_allowed_list", platform: { shared_libs: ["libfoo"], }, }`), }, expectedErrors: []string{ - `module "outside_whitelist": violates neverallow`, + `module "outside_allowed_list": violates neverallow`, }, }, { diff --git a/android/override_module.go b/android/override_module.go index 9f5127dc3..7e58890d7 100644 --- a/android/override_module.go +++ b/android/override_module.go @@ -208,7 +208,21 @@ var overrideBaseDepTag overrideBaseDependencyTag // next phase. func overrideModuleDepsMutator(ctx BottomUpMutatorContext) { if module, ok := ctx.Module().(OverrideModule); ok { - ctx.AddDependency(ctx.Module(), overrideBaseDepTag, *module.getOverrideModuleProperties().Base) + // Skip this overriding module if there's a prebuilt module that overrides it with prefer flag. + overriddenByPrebuilt := false + ctx.VisitDirectDepsWithTag(PrebuiltDepTag, func(dep Module) { + prebuilt, ok := dep.(PrebuiltInterface) + if !ok { + panic("PrebuiltDepTag leads to a non-prebuilt module " + dep.Name()) + } + if prebuilt.Prebuilt().UsePrebuilt() { + overriddenByPrebuilt = true + return + } + }) + if !overriddenByPrebuilt { + ctx.AddDependency(ctx.Module(), overrideBaseDepTag, *module.getOverrideModuleProperties().Base) + } } } diff --git a/android/paths.go b/android/paths.go index 3ad27acbe..bed6f3f58 100644 --- a/android/paths.go +++ b/android/paths.go @@ -405,7 +405,7 @@ func expandOneSrcPath(ctx ModuleContext, s string, expandedExcludes []string) (P p := pathForModuleSrc(ctx, s) if exists, _, err := ctx.Config().fs.Exists(p.String()); err != nil { reportPathErrorf(ctx, "%s: %s", p, err.Error()) - } else if !exists { + } else if !exists && !ctx.Config().testAllowNonExistentPaths { reportPathErrorf(ctx, "module source path %q does not exist", p) } @@ -798,7 +798,7 @@ func PathForSource(ctx PathContext, pathComponents ...string) SourcePath { } } else if exists, _, err := ctx.Config().fs.Exists(path.String()); err != nil { reportPathErrorf(ctx, "%s: %s", path, err.Error()) - } else if !exists { + } else if !exists && !ctx.Config().testAllowNonExistentPaths { reportPathErrorf(ctx, "source path %q does not exist", path) } return path diff --git a/android/phony.go b/android/phony.go new file mode 100644 index 000000000..f8e5a4401 --- /dev/null +++ b/android/phony.go @@ -0,0 +1,75 @@ +// 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 android + +import ( + "sync" + + "github.com/google/blueprint" +) + +var phonyMapOnceKey = NewOnceKey("phony") + +type phonyMap map[string]Paths + +var phonyMapLock sync.Mutex + +func getPhonyMap(config Config) phonyMap { + return config.Once(phonyMapOnceKey, func() interface{} { + return make(phonyMap) + }).(phonyMap) +} + +func addPhony(config Config, name string, deps ...Path) { + phonyMap := getPhonyMap(config) + phonyMapLock.Lock() + defer phonyMapLock.Unlock() + phonyMap[name] = append(phonyMap[name], deps...) +} + +type phonySingleton struct { + phonyMap phonyMap + phonyList []string +} + +var _ SingletonMakeVarsProvider = (*phonySingleton)(nil) + +func (p *phonySingleton) GenerateBuildActions(ctx SingletonContext) { + p.phonyMap = getPhonyMap(ctx.Config()) + p.phonyList = SortedStringKeys(p.phonyMap) + for _, phony := range p.phonyList { + p.phonyMap[phony] = SortedUniquePaths(p.phonyMap[phony]) + } + + if !ctx.Config().EmbeddedInMake() { + for _, phony := range p.phonyList { + ctx.Build(pctx, BuildParams{ + Rule: blueprint.Phony, + Outputs: []WritablePath{PathForPhony(ctx, phony)}, + Implicits: p.phonyMap[phony], + }) + } + } +} + +func (p phonySingleton) MakeVars(ctx MakeVarsContext) { + for _, phony := range p.phonyList { + ctx.Phony(phony, p.phonyMap[phony]...) + } +} + +func phonySingletonFactory() Singleton { + return &phonySingleton{} +} diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go index b568f781d..8029b85bd 100644 --- a/android/prebuilt_test.go +++ b/android/prebuilt_test.go @@ -155,6 +155,44 @@ var prebuiltsTests = []struct { }`, prebuilt: []OsClass{Host}, }, + { + name: "prebuilt override not preferred", + modules: ` + source { + name: "baz", + } + + override_source { + name: "bar", + base: "baz", + } + + prebuilt { + name: "bar", + prefer: false, + srcs: ["prebuilt_file"], + }`, + prebuilt: nil, + }, + { + name: "prebuilt override preferred", + modules: ` + source { + name: "baz", + } + + override_source { + name: "bar", + base: "baz", + } + + prebuilt { + name: "bar", + prefer: true, + srcs: ["prebuilt_file"], + }`, + prebuilt: []OsClass{Device, Host}, + }, } func TestPrebuilts(t *testing.T) { @@ -256,8 +294,10 @@ func TestPrebuilts(t *testing.T) { func registerTestPrebuiltBuildComponents(ctx RegistrationContext) { ctx.RegisterModuleType("prebuilt", newPrebuiltModule) ctx.RegisterModuleType("source", newSourceModule) + ctx.RegisterModuleType("override_source", newOverrideSourceModule) RegisterPrebuiltMutators(ctx) + ctx.PostDepsMutators(RegisterOverridePostDepsMutators) } type prebuiltModule struct { @@ -300,11 +340,15 @@ func (p *prebuiltModule) OutputFiles(tag string) (Paths, error) { } } +type sourceModuleProperties struct { + Deps []string `android:"path,arch_variant"` +} + type sourceModule struct { ModuleBase - properties struct { - Deps []string `android:"path,arch_variant"` - } + OverridableModuleBase + + properties sourceModuleProperties dependsOnSourceModule, dependsOnPrebuiltModule bool deps Paths src Path @@ -314,10 +358,11 @@ func newSourceModule() Module { m := &sourceModule{} m.AddProperties(&m.properties) InitAndroidArchModule(m, HostAndDeviceDefault, MultilibCommon) + InitOverridableModule(m, nil) return m } -func (s *sourceModule) DepsMutator(ctx BottomUpMutatorContext) { +func (s *sourceModule) OverridablePropertiesDepsMutator(ctx BottomUpMutatorContext) { // s.properties.Deps are annotated with android:path, so they are // automatically added to the dependency by pathDeps mutator } @@ -330,3 +375,20 @@ func (s *sourceModule) GenerateAndroidBuildActions(ctx ModuleContext) { func (s *sourceModule) Srcs() Paths { return Paths{s.src} } + +type overrideSourceModule struct { + ModuleBase + OverrideModuleBase +} + +func (o *overrideSourceModule) GenerateAndroidBuildActions(_ ModuleContext) { +} + +func newOverrideSourceModule() Module { + m := &overrideSourceModule{} + m.AddProperties(&sourceModuleProperties{}) + + InitAndroidArchModule(m, HostAndDeviceDefault, MultilibCommon) + InitOverrideModule(m) + return m +} diff --git a/android/register.go b/android/register.go index ccfe01e74..036a8113f 100644 --- a/android/register.go +++ b/android/register.go @@ -104,6 +104,9 @@ func (ctx *Context) Register() { registerMutators(ctx.Context, preArch, preDeps, postDeps, finalDeps) + // Register phony just before makevars so it can write out its phony rules as Make rules + ctx.RegisterSingletonType("phony", SingletonFactoryAdaptor(phonySingletonFactory)) + // Register makevars after other singletons so they can export values through makevars ctx.RegisterSingletonType("makevars", SingletonFactoryAdaptor(makeVarsSingletonFunc)) diff --git a/android/singleton.go b/android/singleton.go index 568398cdd..2c51c6c48 100644 --- a/android/singleton.go +++ b/android/singleton.go @@ -36,6 +36,12 @@ type SingletonContext interface { Variable(pctx PackageContext, name, value string) Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule Build(pctx PackageContext, params BuildParams) + + // Phony creates a Make-style phony rule, a rule with no commands that can depend on other + // phony rules or real files. Phony can be called on the same name multiple times to add + // additional dependencies. + Phony(name string, deps ...Path) + RequireNinjaVersion(major, minor, micro int) // SetNinjaBuildDir sets the value of the top-level "builddir" Ninja variable @@ -156,6 +162,10 @@ func (s *singletonContextAdaptor) Build(pctx PackageContext, params BuildParams) } +func (s *singletonContextAdaptor) Phony(name string, deps ...Path) { + addPhony(s.Config(), name, deps...) +} + func (s *singletonContextAdaptor) SetNinjaBuildDir(pctx PackageContext, value string) { s.SingletonContext.SetNinjaBuildDir(pctx.PackageContext, value) } diff --git a/android/variable.go b/android/variable.go index 3c08405dd..b69d4254d 100644 --- a/android/variable.go +++ b/android/variable.go @@ -272,10 +272,6 @@ type productVariables struct { CoveragePaths []string `json:",omitempty"` CoverageExcludePaths []string `json:",omitempty"` - DevicePrefer32BitApps *bool `json:",omitempty"` - DevicePrefer32BitExecutables *bool `json:",omitempty"` - HostPrefer32BitExecutables *bool `json:",omitempty"` - SanitizeHost []string `json:",omitempty"` SanitizeDevice []string `json:",omitempty"` SanitizeDeviceDiag []string `json:",omitempty"` @@ -323,7 +319,7 @@ type productVariables struct { PackageNameOverrides []string `json:",omitempty"` EnforceSystemCertificate *bool `json:",omitempty"` - EnforceSystemCertificateWhitelist []string `json:",omitempty"` + EnforceSystemCertificateAllowList []string `json:",omitempty"` ProductHiddenAPIStubs []string `json:",omitempty"` ProductHiddenAPIStubsSystem []string `json:",omitempty"` diff --git a/android/writedocs.go b/android/writedocs.go index 7262ad810..9e43e80a6 100644 --- a/android/writedocs.go +++ b/android/writedocs.go @@ -69,9 +69,5 @@ func (c *docsSingleton) GenerateBuildActions(ctx SingletonContext) { }) // Add a phony target for building the documentation - ctx.Build(pctx, BuildParams{ - Rule: blueprint.Phony, - Output: PathForPhony(ctx, "soong_docs"), - Input: docsFile, - }) + ctx.Phony("soong_docs", docsFile) } diff --git a/apex/androidmk.go b/apex/androidmk.go index 1b3a4ba10..774b62d99 100644 --- a/apex/androidmk.go +++ b/apex/androidmk.go @@ -180,13 +180,17 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, mo } switch fi.class { case javaSharedLib: - javaModule := fi.module.(java.Dependency) // soong_java_prebuilt.mk sets LOCAL_MODULE_SUFFIX := .jar Therefore // 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")) - fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", javaModule.ImplementationAndResourcesJars()[0].String()) - fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", javaModule.HeaderJars()[0].String()) + if javaModule, ok := fi.module.(java.Dependency); ok { + fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", javaModule.ImplementationAndResourcesJars()[0].String()) + fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", javaModule.HeaderJars()[0].String()) + } else { + fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", fi.builtFile.String()) + fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", fi.builtFile.String()) + } fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", fi.builtFile.String()) fmt.Fprintln(w, "LOCAL_DEX_PREOPT := false") fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_java_prebuilt.mk") diff --git a/apex/apex.go b/apex/apex.go index 2f7b2e535..3fef1ee41 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -64,13 +64,14 @@ var ( usesTag = dependencyTag{name: "uses"} androidAppTag = dependencyTag{name: "androidApp", payload: true} rroTag = dependencyTag{name: "rro", payload: true} - apexAvailWl = makeApexAvailableWhitelist() - inverseApexAvailWl = invertApexWhiteList(apexAvailWl) + apexAvailBaseline = makeApexAvailableBaseline() + + inverseApexAvailBaseline = invertApexBaseline(apexAvailBaseline) ) // Transform the map of apex -> modules to module -> apexes. -func invertApexWhiteList(m map[string][]string) map[string][]string { +func invertApexBaseline(m map[string][]string) map[string][]string { r := make(map[string][]string) for apex, modules := range m { for _, module := range modules { @@ -80,16 +81,16 @@ func invertApexWhiteList(m map[string][]string) map[string][]string { return r } -// Retrieve the while list of apexes to which the supplied module belongs. -func WhitelistedApexAvailable(moduleName string) []string { - return inverseApexAvailWl[normalizeModuleName(moduleName)] +// Retrieve the baseline of apexes to which the supplied module belongs. +func BaselineApexAvailable(moduleName string) []string { + return inverseApexAvailBaseline[normalizeModuleName(moduleName)] } // This is a map from apex to modules, which overrides the // apex_available setting for that particular module to make // it available for the apex regardless of its setting. // TODO(b/147364041): remove this -func makeApexAvailableWhitelist() map[string][]string { +func makeApexAvailableBaseline() map[string][]string { // The "Module separator"s below are employed to minimize merge conflicts. m := make(map[string][]string) // @@ -871,17 +872,17 @@ func apexUsesMutator(mctx android.BottomUpMutatorContext) { } var ( - useVendorWhitelistKey = android.NewOnceKey("useVendorWhitelist") + useVendorAllowListKey = android.NewOnceKey("useVendorAllowList") ) -// useVendorWhitelist returns the list of APEXes which are allowed to use_vendor. +// useVendorAllowList returns the list of APEXes which are allowed to use_vendor. // When use_vendor is used, native modules are built with __ANDROID_VNDK__ and __ANDROID_APEX__, // which may cause compatibility issues. (e.g. libbinder) // Even though libbinder restricts its availability via 'apex_available' property and relies on // yet another macro __ANDROID_APEX_<NAME>__, we restrict usage of "use_vendor:" from other APEX modules // to avoid similar problems. -func useVendorWhitelist(config android.Config) []string { - return config.Once(useVendorWhitelistKey, func() interface{} { +func useVendorAllowList(config android.Config) []string { + return config.Once(useVendorAllowListKey, func() interface{} { return []string{ // swcodec uses "vendor" variants for smaller size "com.android.media.swcodec", @@ -890,11 +891,11 @@ func useVendorWhitelist(config android.Config) []string { }).([]string) } -// setUseVendorWhitelistForTest overrides useVendorWhitelist and must be -// called before the first call to useVendorWhitelist() -func setUseVendorWhitelistForTest(config android.Config, whitelist []string) { - config.Once(useVendorWhitelistKey, func() interface{} { - return whitelist +// setUseVendorAllowListForTest overrides useVendorAllowList and must be +// called before the first call to useVendorAllowList() +func setUseVendorAllowListForTest(config android.Config, allowList []string) { + config.Once(useVendorAllowListKey, func() interface{} { + return allowList }) } @@ -992,7 +993,7 @@ type apexBundleProperties struct { // 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 whitelisted to be included in this APEX. + // 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. @@ -1332,7 +1333,7 @@ func (a *apexBundle) combineProperties(ctx android.BottomUpMutatorContext) { } func (a *apexBundle) DepsMutator(ctx android.BottomUpMutatorContext) { - if proptools.Bool(a.properties.Use_vendor) && !android.InList(a.Name(), useVendorWhitelist(ctx.Config())) { + if proptools.Bool(a.properties.Use_vendor) && !android.InList(a.Name(), useVendorAllowList(ctx.Config())) { ctx.PropertyErrorf("use_vendor", "not allowed to set use_vendor: true") } @@ -1804,7 +1805,7 @@ func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) { return false } - if to.AvailableFor(apexName) || whitelistedApexAvailable(apexName, toName) { + if to.AvailableFor(apexName) || baselineApexAvailable(apexName, toName) { return true } ctx.ModuleErrorf("%q requires %q that is not available for the APEX. Dependency path:%s", fromName, toName, ctx.GetPathString(true)) @@ -2243,16 +2244,16 @@ func (a *apexBundle) checkJavaStableSdkVersion(ctx android.ModuleContext) { }) } -func whitelistedApexAvailable(apex, moduleName string) bool { +func baselineApexAvailable(apex, moduleName string) bool { key := apex moduleName = normalizeModuleName(moduleName) - if val, ok := apexAvailWl[key]; ok && android.InList(moduleName, val) { + if val, ok := apexAvailBaseline[key]; ok && android.InList(moduleName, val) { return true } key = android.AvailableToAnyApex - if val, ok := apexAvailWl[key]; ok && android.InList(moduleName, val) { + if val, ok := apexAvailBaseline[key]; ok && android.InList(moduleName, val) { return true } @@ -2280,9 +2281,6 @@ func newApexBundle() *apexBundle { module.AddProperties(&module.properties) module.AddProperties(&module.targetProperties) module.AddProperties(&module.overridableProperties) - module.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase, class android.OsClass) bool { - return class == android.Device && ctx.Config().DevicePrefer32BitExecutables() - }) android.InitAndroidMultiTargetsArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon) android.InitDefaultableModule(module) android.InitSdkAwareModule(module) diff --git a/apex/apex_test.go b/apex/apex_test.go index d6a5d0909..609e6516b 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -329,7 +329,7 @@ func ensureListEmpty(t *testing.T, result []string) { // Minimal test func TestBasicApex(t *testing.T) { - ctx, _ := testApex(t, ` + ctx, config := testApex(t, ` apex_defaults { name: "myapex-defaults", manifest: ":myapex.manifest", @@ -484,6 +484,16 @@ func TestBasicApex(t *testing.T) { apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule") + // Make sure that Android.mk is created + ab := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) + data := android.AndroidMkDataForTest(t, config, "", ab) + var builder strings.Builder + data.Custom(&builder, ab.BaseModuleName(), "TARGET_", "", data) + + androidMk := builder.String() + ensureContains(t, androidMk, "LOCAL_MODULE := mylib.myapex\n") + ensureNotContains(t, androidMk, "LOCAL_MODULE := mylib.com.android.myapex\n") + optFlags := apexRule.Args["opt_flags"] ensureContains(t, optFlags, "--pubkey vendor/foo/devkeys/testkey.avbpubkey") // Ensure that the NOTICE output is being packaged as an asset. @@ -1133,7 +1143,7 @@ func TestApexDependsOnLLNDKTransitively(t *testing.T) { symbol_file: "", } `, func(fs map[string][]byte, config android.Config) { - setUseVendorWhitelistForTest(config, []string{"myapex"}) + setUseVendorAllowListForTest(config, []string{"myapex"}) }, withUnbundledBuild) // Ensure that LLNDK dep is not included @@ -1860,7 +1870,7 @@ func TestUseVendor(t *testing.T) { apex_available: [ "myapex" ], } `, func(fs map[string][]byte, config android.Config) { - setUseVendorWhitelistForTest(config, []string{"myapex"}) + setUseVendorAllowListForTest(config, []string{"myapex"}) }) inputsList := []string{} @@ -1893,9 +1903,9 @@ func TestUseVendorRestriction(t *testing.T) { private_key: "testkey.pem", } `, func(fs map[string][]byte, config android.Config) { - setUseVendorWhitelistForTest(config, []string{""}) + setUseVendorAllowListForTest(config, []string{""}) }) - // no error with whitelist + // no error with allow list testApex(t, ` apex { name: "myapex", @@ -1908,7 +1918,7 @@ func TestUseVendorRestriction(t *testing.T) { private_key: "testkey.pem", } `, func(fs map[string][]byte, config android.Config) { - setUseVendorWhitelistForTest(config, []string{"myapex"}) + setUseVendorAllowListForTest(config, []string{"myapex"}) }) } @@ -3673,7 +3683,7 @@ func TestApexUsesFailsIfUseVenderMismatch(t *testing.T) { private_key: "testkey.pem", } `, func(fs map[string][]byte, config android.Config) { - setUseVendorWhitelistForTest(config, []string{"myapex"}) + setUseVendorAllowListForTest(config, []string{"myapex"}) }) } diff --git a/apex/builder.go b/apex/builder.go index 17eac1a39..129358834 100644 --- a/apex/builder.go +++ b/apex/builder.go @@ -165,13 +165,13 @@ var ( diffApexContentRule = pctx.StaticRule("diffApexContentRule", blueprint.RuleParams{ Command: `diff --unchanged-group-format='' \` + `--changed-group-format='%<' \` + - `${image_content_file} ${whitelisted_files_file} || (` + + `${image_content_file} ${allowed_files_file} || (` + `echo -e "New unexpected files were added to ${apex_module_name}." ` + ` "To fix the build run following command:" && ` + - `echo "system/apex/tools/update_whitelist.sh ${whitelisted_files_file} ${image_content_file}" && ` + + `echo "system/apex/tools/update_allowed_list.sh ${allowed_files_file} ${image_content_file}" && ` + `exit 1); touch ${out}`, - Description: "Diff ${image_content_file} and ${whitelisted_files_file}", - }, "image_content_file", "whitelisted_files_file", "apex_module_name") + Description: "Diff ${image_content_file} and ${allowed_files_file}", + }, "image_content_file", "allowed_files_file", "apex_module_name") ) func (a *apexBundle) buildManifest(ctx android.ModuleContext, provideNativeLibs, requireNativeLibs []string) { @@ -402,7 +402,7 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { }, }) implicitInputs = append(implicitInputs, imageContentFile) - whitelistedFilesFile := android.PathForModuleSrc(ctx, proptools.String(a.properties.Whitelisted_files)) + allowedFilesFile := android.PathForModuleSrc(ctx, proptools.String(a.properties.Whitelisted_files)) phonyOutput := android.PathForModuleOut(ctx, a.Name()+"-diff-phony-output") ctx.Build(pctx, android.BuildParams{ @@ -411,9 +411,9 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { Output: phonyOutput, Description: "diff apex image content", Args: map[string]string{ - "whitelisted_files_file": whitelistedFilesFile.String(), - "image_content_file": imageContentFile.String(), - "apex_module_name": a.Name(), + "allowed_files_file": allowedFilesFile.String(), + "image_content_file": imageContentFile.String(), + "apex_module_name": a.Name(), }, }) diff --git a/cc/androidmk.go b/cc/androidmk.go index 52480ea68..b3ad610d6 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -457,6 +457,9 @@ func (c *stubDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android. entries.SetString("LOCAL_MODULE_PATH", path) entries.SetString("LOCAL_MODULE_STEM", stem) entries.SetBool("LOCAL_NO_NOTICE_FILE", true) + if c.parsedCoverageXmlPath.String() != "" { + entries.SetString("SOONG_NDK_API_XML", "$(SOONG_NDK_API_XML) "+c.parsedCoverageXmlPath.String()) + } }) } @@ -825,15 +825,8 @@ func (c *Module) Init() android.Module { } c.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase, class android.OsClass) bool { - switch class { - case android.Device: - return ctx.Config().DevicePrefer32BitExecutables() - case android.HostCross: - // Windows builds always prefer 32-bit - return true - default: - return false - } + // Windows builds always prefer 32-bit + return class == android.HostCross }) android.InitAndroidArchModule(c, c.hod, c.multilib) android.InitApexModule(c) @@ -3230,12 +3223,7 @@ func (ks *kytheExtractAllSingleton) GenerateBuildActions(ctx android.SingletonCo }) // TODO(asmundak): Perhaps emit a rule to output a warning if there were no xrefTargets if len(xrefTargets) > 0 { - ctx.Build(pctx, android.BuildParams{ - Rule: blueprint.Phony, - Output: android.PathForPhony(ctx, "xref_cxx"), - Inputs: xrefTargets, - //Default: true, - }) + ctx.Phony("xref_cxx", xrefTargets...) } } diff --git a/cc/compiler.go b/cc/compiler.go index e7495da88..b5f297ce5 100644 --- a/cc/compiler.go +++ b/cc/compiler.go @@ -514,7 +514,7 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps flags.Local.CFlags = append(flags.Local.CFlags, "-fopenmp") } - // Exclude directories from manual binder interface whitelisting. + // Exclude directories from manual binder interface allowed list. //TODO(b/145621474): Move this check into IInterface.h when clang-tidy no longer uses absolute paths. if android.HasAnyPrefix(ctx.ModuleDir(), allowedManualInterfacePaths) { flags.Local.CFlags = append(flags.Local.CFlags, "-DDO_NOT_CHECK_MANUAL_BINDER_INTERFACES") diff --git a/cc/config/global.go b/cc/config/global.go index 1dd8a2d03..7b651bc84 100644 --- a/cc/config/global.go +++ b/cc/config/global.go @@ -128,8 +128,8 @@ var ( // prebuilts/clang default settings. ClangDefaultBase = "prebuilts/clang/host" - ClangDefaultVersion = "clang-r383902" - ClangDefaultShortVersion = "11.0.1" + ClangDefaultVersion = "clang-r383902b" + ClangDefaultShortVersion = "11.0.2" // Directories with warnings from Android.bp files. WarningAllowedProjects = []string{ diff --git a/cc/linker.go b/cc/linker.go index 57a0c016a..c9cbd9baf 100644 --- a/cc/linker.go +++ b/cc/linker.go @@ -177,7 +177,10 @@ type BaseLinkerProperties struct { Version_script *string `android:"path,arch_variant"` // list of static libs that should not be used to build this module - Exclude_static_libs []string + Exclude_static_libs []string `android:"arch_variant"` + + // list of shared libs that should not be used to build this module + Exclude_shared_libs []string `android:"arch_variant"` } func NewBaseLinker(sanitize *sanitize) *baseLinker { @@ -223,6 +226,8 @@ func (linker *baseLinker) linkerDeps(ctx DepsContext, deps Deps) Deps { deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, linker.Properties.Export_shared_lib_headers...) deps.ReexportGeneratedHeaders = append(deps.ReexportGeneratedHeaders, linker.Properties.Export_generated_headers...) + deps.SharedLibs = removeListFromList(deps.SharedLibs, linker.Properties.Exclude_shared_libs) + deps.StaticLibs = removeListFromList(deps.StaticLibs, linker.Properties.Exclude_static_libs) deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Exclude_static_libs) if Bool(linker.Properties.Use_version_lib) { diff --git a/cc/ndk_library.go b/cc/ndk_library.go index 1597b88d0..d79badbc4 100644 --- a/cc/ndk_library.go +++ b/cc/ndk_library.go @@ -25,8 +25,12 @@ import ( "android/soong/android" ) +func init() { + pctx.HostBinToolVariable("ndk_api_coverage_parser", "ndk_api_coverage_parser") +} + var ( - toolPath = pctx.SourcePathVariable("toolPath", "build/soong/cc/gen_stub_libs.py") + toolPath = pctx.SourcePathVariable("toolPath", "build/soong/cc/scriptlib/gen_stub_libs.py") genStubSrc = pctx.AndroidStaticRule("genStubSrc", blueprint.RuleParams{ @@ -35,6 +39,12 @@ var ( CommandDeps: []string{"$toolPath"}, }, "arch", "apiLevel", "apiMap", "flags") + parseNdkApiRule = pctx.AndroidStaticRule("parseNdkApiRule", + blueprint.RuleParams{ + Command: "$ndk_api_coverage_parser $in $out --api-map $apiMap", + CommandDeps: []string{"$ndk_api_coverage_parser"}, + }, "apiMap") + ndkLibrarySuffix = ".ndk" ndkPrebuiltSharedLibs = []string{ @@ -111,8 +121,9 @@ type stubDecorator struct { properties libraryProperties - versionScriptPath android.ModuleGenPath - installPath android.Path + versionScriptPath android.ModuleGenPath + parsedCoverageXmlPath android.ModuleOutPath + installPath android.Path } // OMG GO @@ -308,14 +319,35 @@ func compileStubLibrary(ctx ModuleContext, flags Flags, symbolFile, apiLevel, ge return compileObjs(ctx, flagsToBuilderFlags(flags), subdir, srcs, nil, nil), versionScriptPath } +func parseSymbolFileForCoverage(ctx ModuleContext, symbolFile string) android.ModuleOutPath { + apiLevelsJson := android.GetApiLevelsJson(ctx) + symbolFilePath := android.PathForModuleSrc(ctx, symbolFile) + outputFileName := strings.Split(symbolFilePath.Base(), ".")[0] + parsedApiCoveragePath := android.PathForModuleOut(ctx, outputFileName+".xml") + ctx.Build(pctx, android.BuildParams{ + Rule: parseNdkApiRule, + Description: "parse ndk api symbol file for api coverage: " + symbolFilePath.Rel(), + Outputs: []android.WritablePath{parsedApiCoveragePath}, + Input: symbolFilePath, + Args: map[string]string{ + "apiMap": apiLevelsJson.String(), + }, + }) + return parsedApiCoveragePath +} + func (c *stubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects { if !strings.HasSuffix(String(c.properties.Symbol_file), ".map.txt") { ctx.PropertyErrorf("symbol_file", "must end with .map.txt") } - objs, versionScript := compileStubLibrary(ctx, flags, String(c.properties.Symbol_file), + symbolFile := String(c.properties.Symbol_file) + objs, versionScript := compileStubLibrary(ctx, flags, symbolFile, c.properties.ApiLevel, "") c.versionScriptPath = versionScript + if c.properties.ApiLevel == "current" && ctx.PrimaryArch() { + c.parsedCoverageXmlPath = parseSymbolFileForCoverage(ctx, symbolFile) + } return objs } diff --git a/cc/scriptlib/Android.bp b/cc/scriptlib/Android.bp new file mode 100644 index 000000000..ff9a2f0f3 --- /dev/null +++ b/cc/scriptlib/Android.bp @@ -0,0 +1,32 @@ +// +// Copyright (C) 2020 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. +// + +python_test_host { + name: "test_ndk_api_coverage_parser", + main: "test_ndk_api_coverage_parser.py", + srcs: [ + "test_ndk_api_coverage_parser.py", + ], +} + +python_binary_host { + name: "ndk_api_coverage_parser", + main: "ndk_api_coverage_parser.py", + srcs: [ + "gen_stub_libs.py", + "ndk_api_coverage_parser.py", + ], +} diff --git a/cc/scriptlib/__init__.py b/cc/scriptlib/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/cc/scriptlib/__init__.py diff --git a/cc/gen_stub_libs.py b/cc/scriptlib/gen_stub_libs.py index 7deb804c3..d61dfbb07 100755 --- a/cc/gen_stub_libs.py +++ b/cc/scriptlib/gen_stub_libs.py @@ -246,6 +246,7 @@ class Symbol(object): def __eq__(self, other): return self.name == other.name and set(self.tags) == set(other.tags) + class SymbolFileParser(object): """Parses NDK symbol files.""" def __init__(self, input_file, api_map, arch, api, llndk, apex): diff --git a/cc/scriptlib/ndk_api_coverage_parser.py b/cc/scriptlib/ndk_api_coverage_parser.py new file mode 100755 index 000000000..d74035b2a --- /dev/null +++ b/cc/scriptlib/ndk_api_coverage_parser.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python +# +# Copyright (C) 2020 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. +# +"""Generates xml of NDK libraries used for API coverage analysis.""" +import argparse +import json +import os +import sys + +from xml.etree.ElementTree import Element, SubElement, tostring +from gen_stub_libs import ALL_ARCHITECTURES, FUTURE_API_LEVEL, MultiplyDefinedSymbolError, SymbolFileParser + + +ROOT_ELEMENT_TAG = 'ndk-library' +SYMBOL_ELEMENT_TAG = 'symbol' +ARCHITECTURE_ATTRIBUTE_KEY = 'arch' +DEPRECATED_ATTRIBUTE_KEY = 'is_deprecated' +PLATFORM_ATTRIBUTE_KEY = 'is_platform' +NAME_ATTRIBUTE_KEY = 'name' +VARIABLE_TAG = 'var' +EXPOSED_TARGET_TAGS = ( + 'vndk', + 'apex', + 'llndk', +) +API_LEVEL_TAG_PREFIXES = ( + 'introduced=', + 'introduced-', +) + + +def parse_tags(tags): + """Parses tags and save needed tags in the created attributes. + + Return attributes dictionary. + """ + attributes = {} + arch = [] + for tag in tags: + if tag.startswith(tuple(API_LEVEL_TAG_PREFIXES)): + key, _, value = tag.partition('=') + attributes.update({key: value}) + elif tag in ALL_ARCHITECTURES: + arch.append(tag) + elif tag in EXPOSED_TARGET_TAGS: + attributes.update({tag: 'True'}) + attributes.update({ARCHITECTURE_ATTRIBUTE_KEY: ','.join(arch)}) + return attributes + + +class XmlGenerator(object): + """Output generator that writes parsed symbol file to a xml file.""" + def __init__(self, output_file): + self.output_file = output_file + + def convertToXml(self, versions): + """Writes all symbol data to the output file.""" + root = Element(ROOT_ELEMENT_TAG) + for version in versions: + if VARIABLE_TAG in version.tags: + continue + version_attributes = parse_tags(version.tags) + _, _, postfix = version.name.partition('_') + is_platform = postfix == 'PRIVATE' or postfix == 'PLATFORM' + is_deprecated = postfix == 'DEPRECATED' + version_attributes.update({PLATFORM_ATTRIBUTE_KEY: str(is_platform)}) + version_attributes.update({DEPRECATED_ATTRIBUTE_KEY: str(is_deprecated)}) + for symbol in version.symbols: + if VARIABLE_TAG in symbol.tags: + continue + attributes = {NAME_ATTRIBUTE_KEY: symbol.name} + attributes.update(version_attributes) + # If same version tags already exist, it will be overwrite here. + attributes.update(parse_tags(symbol.tags)) + SubElement(root, SYMBOL_ELEMENT_TAG, attributes) + return root + + def write_xml_to_file(self, root): + """Write xml element root to output_file.""" + parsed_data = tostring(root) + output_file = open(self.output_file, "wb") + output_file.write(parsed_data) + + def write(self, versions): + root = self.convertToXml(versions) + self.write_xml_to_file(root) + + +def parse_args(): + """Parses and returns command line arguments.""" + parser = argparse.ArgumentParser() + + parser.add_argument('symbol_file', type=os.path.realpath, help='Path to symbol file.') + parser.add_argument( + 'output_file', type=os.path.realpath, + help='The output parsed api coverage file.') + parser.add_argument( + '--api-map', type=os.path.realpath, required=True, + help='Path to the API level map JSON file.') + return parser.parse_args() + + +def main(): + """Program entry point.""" + args = parse_args() + + with open(args.api_map) as map_file: + api_map = json.load(map_file) + + with open(args.symbol_file) as symbol_file: + try: + versions = SymbolFileParser(symbol_file, api_map, "", FUTURE_API_LEVEL, + True, True).parse() + except MultiplyDefinedSymbolError as ex: + sys.exit('{}: error: {}'.format(args.symbol_file, ex)) + + generator = XmlGenerator(args.output_file) + generator.write(versions) + +if __name__ == '__main__': + main() diff --git a/cc/test_gen_stub_libs.py b/cc/scriptlib/test_gen_stub_libs.py index 0b45e7110..0b45e7110 100755 --- a/cc/test_gen_stub_libs.py +++ b/cc/scriptlib/test_gen_stub_libs.py diff --git a/cc/scriptlib/test_ndk_api_coverage_parser.py b/cc/scriptlib/test_ndk_api_coverage_parser.py new file mode 100644 index 000000000..a3c9b708c --- /dev/null +++ b/cc/scriptlib/test_ndk_api_coverage_parser.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python +# +# Copyright (C) 2016 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. +# +"""Tests for ndk_api_coverage_parser.py.""" +import io +import textwrap +import unittest + +from xml.etree.ElementTree import tostring +from gen_stub_libs import FUTURE_API_LEVEL, SymbolFileParser +import ndk_api_coverage_parser as nparser + + +# pylint: disable=missing-docstring + + +class ApiCoverageSymbolFileParserTest(unittest.TestCase): + def test_parse(self): + input_file = io.StringIO(textwrap.dedent(u"""\ + LIBLOG { # introduced-arm64=24 introduced-x86=24 introduced-x86_64=24 + global: + android_name_to_log_id; # apex llndk introduced=23 + android_log_id_to_name; # llndk arm + __android_log_assert; # introduced-x86=23 + __android_log_buf_print; # var + __android_log_buf_write; + local: + *; + }; + + LIBLOG_PLATFORM { + android_fdtrack; # llndk + android_net; # introduced=23 + }; + + LIBLOG_FOO { # var + android_var; + }; + """)) + parser = SymbolFileParser(input_file, {}, "", FUTURE_API_LEVEL, True, True) + generator = nparser.XmlGenerator(io.StringIO()) + result = tostring(generator.convertToXml(parser.parse())).decode() + expected = '<ndk-library><symbol apex="True" arch="" introduced="23" introduced-arm64="24" introduced-x86="24" introduced-x86_64="24" is_deprecated="False" is_platform="False" llndk="True" name="android_name_to_log_id" /><symbol arch="arm" introduced-arm64="24" introduced-x86="24" introduced-x86_64="24" is_deprecated="False" is_platform="False" llndk="True" name="android_log_id_to_name" /><symbol arch="" introduced-arm64="24" introduced-x86="23" introduced-x86_64="24" is_deprecated="False" is_platform="False" name="__android_log_assert" /><symbol arch="" introduced-arm64="24" introduced-x86="24" introduced-x86_64="24" is_deprecated="False" is_platform="False" name="__android_log_buf_write" /><symbol arch="" is_deprecated="False" is_platform="True" llndk="True" name="android_fdtrack" /><symbol arch="" introduced="23" is_deprecated="False" is_platform="True" name="android_net" /></ndk-library>' + self.assertEqual(expected, result) + + +def main(): + suite = unittest.TestLoader().loadTestsFromName(__name__) + unittest.TextTestRunner(verbosity=3).run(suite) + + +if __name__ == '__main__': + main() @@ -43,6 +43,7 @@ func sdkMutator(ctx android.BottomUpMutatorContext) { if ctx.Config().UnbundledBuild() { modules[0].(*Module).Properties.HideFromMake = true + modules[0].(*Module).Properties.PreventInstall = true } else { modules[1].(*Module).Properties.SdkAndPlatformVariantVisibleToMake = true modules[1].(*Module).Properties.PreventInstall = true diff --git a/cc/testing.go b/cc/testing.go index edbb24d13..479b424ab 100644 --- a/cc/testing.go +++ b/cc/testing.go @@ -467,15 +467,6 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { } func GatherRequiredFilesForTest(fs map[string][]byte) { - fs["prebuilts/ndk/current/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libc++_shared.so"] = nil - fs["prebuilts/ndk/current/platforms/android-27/arch-arm/usr/lib/crtbegin_so.o"] = nil - fs["prebuilts/ndk/current/platforms/android-27/arch-arm/usr/lib/crtend_so.o"] = nil - fs["prebuilts/ndk/current/platforms/android-27/arch-arm64/usr/lib/crtbegin_so.o"] = nil - fs["prebuilts/ndk/current/platforms/android-27/arch-arm64/usr/lib/crtend_so.o"] = nil - fs["prebuilts/ndk/current/platforms/android-27/arch-x86/usr/lib/crtbegin_so.o"] = nil - fs["prebuilts/ndk/current/platforms/android-27/arch-x86/usr/lib/crtend_so.o"] = nil - fs["prebuilts/ndk/current/platforms/android-27/arch-x86_64/usr/lib64/crtbegin_so.o"] = nil - fs["prebuilts/ndk/current/platforms/android-27/arch-x86_64/usr/lib64/crtend_so.o"] = nil } func TestConfig(buildDir string, os android.OsType, env map[string]string, @@ -484,20 +475,7 @@ func TestConfig(buildDir string, os android.OsType, env map[string]string, // add some modules that are required by the compiler and/or linker bp = bp + GatherRequiredDepsForTest(os) - mockFS := map[string][]byte{ - "foo.c": nil, - "foo.lds": nil, - "bar.c": nil, - "baz.c": nil, - "baz.o": nil, - "a.proto": nil, - "b.aidl": nil, - "sub/c.aidl": nil, - "my_include": nil, - "foo.map.txt": nil, - "liba.so": nil, - "libb.a": nil, - } + mockFS := map[string][]byte{} GatherRequiredFilesForTest(mockFS) diff --git a/java/aar.go b/java/aar.go index 7413c8082..28e388aaf 100644 --- a/java/aar.go +++ b/java/aar.go @@ -734,6 +734,10 @@ func (a *AARImport) DexJarBuildPath() android.Path { return nil } +func (a *AARImport) DexJarInstallPath() android.Path { + return nil +} + func (a *AARImport) AidlIncludeDirs() android.Paths { return nil } diff --git a/java/app.go b/java/app.go index 24dde79f4..0fdede13a 100755 --- a/java/app.go +++ b/java/app.go @@ -691,9 +691,9 @@ func processMainCert(m android.ModuleBase, certPropValue string, certificates [] systemCertPath := ctx.Config().DefaultAppCertificateDir(ctx).String() if strings.HasPrefix(certPath, systemCertPath) { enforceSystemCert := ctx.Config().EnforceSystemCertificate() - whitelist := ctx.Config().EnforceSystemCertificateWhitelist() + allowed := ctx.Config().EnforceSystemCertificateAllowList() - if enforceSystemCert && !inList(m.Name(), whitelist) { + if enforceSystemCert && !inList(m.Name(), allowed) { ctx.PropertyErrorf("certificate", "The module in product partition cannot be signed with certificate in system.") } } @@ -973,10 +973,6 @@ func AndroidAppFactory() android.Module { &module.overridableAppProperties, &module.usesLibrary.usesLibraryProperties) - module.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase, class android.OsClass) bool { - return class == android.Device && ctx.Config().DevicePrefer32BitApps() - }) - android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) android.InitDefaultableModule(module) android.InitOverridableModule(module, &module.appProperties.Overrides) @@ -1887,16 +1883,22 @@ func (u *usesLibrary) usesLibraryPaths(ctx android.ModuleContext) dexpreopt.Libr ctx.VisitDirectDepsWithTag(usesLibTag, func(m android.Module) { dep := ctx.OtherModuleName(m) if lib, ok := m.(Dependency); ok { - if dexJar := lib.DexJarBuildPath(); dexJar != nil { - usesLibPaths[dep] = &dexpreopt.LibraryPath{ - dexJar, - // TODO(b/132357300): propagate actual install paths here. - filepath.Join("/system/framework", dep+".jar"), - } - } else { + buildPath := lib.DexJarBuildPath() + if buildPath == nil { ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must"+ " produce a dex jar, does it have installable: true?", dep) + return } + + var devicePath string + installPath := lib.DexJarInstallPath() + if installPath == nil { + devicePath = filepath.Join("/system/framework", dep+".jar") + } else { + devicePath = android.InstallPathToOnDevicePath(ctx, installPath.(android.InstallPath)) + } + + usesLibPaths[dep] = &dexpreopt.LibraryPath{buildPath, devicePath} } else if ctx.Config().AllowMissingDependencies() { ctx.AddMissingDependencies([]string{dep}) } else { diff --git a/java/app_test.go b/java/app_test.go index eeba161b3..e45ba70d5 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -2657,7 +2657,7 @@ func TestCodelessApp(t *testing.T) { } func TestEmbedNotice(t *testing.T) { - ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+` + ctx, _ := testJavaWithFS(t, cc.GatherRequiredDepsForTest(android.Android)+` android_app { name: "foo", srcs: ["a.java"], @@ -2713,7 +2713,12 @@ func TestEmbedNotice(t *testing.T) { srcs: ["b.java"], notice: "TOOL_NOTICE", } - `) + `, map[string][]byte{ + "APP_NOTICE": nil, + "GENRULE_NOTICE": nil, + "LIB_NOTICE": nil, + "TOOL_NOTICE": nil, + }) // foo has NOTICE files to process, and embed_notices is true. foo := ctx.ModuleForTests("foo", "android_common") diff --git a/java/device_host_converter.go b/java/device_host_converter.go index 1ffb13f94..9191a8321 100644 --- a/java/device_host_converter.go +++ b/java/device_host_converter.go @@ -51,7 +51,7 @@ type DeviceForHost struct { // java_device_for_host makes the classes.jar output of a device java_library module available to host // java_library modules. // -// It is rarely necessary, and its usage is restricted to a few whitelisted projects. +// It is rarely necessary, and its usage is restricted to a few allowed projects. func DeviceForHostFactory() android.Module { module := &DeviceForHost{} @@ -68,7 +68,7 @@ type HostForDevice struct { // java_host_for_device makes the classes.jar output of a host java_library module available to device // java_library modules. // -// It is rarely necessary, and its usage is restricted to a few whitelisted projects. +// It is rarely necessary, and its usage is restricted to a few allowed projects. func HostForDeviceFactory() android.Module { module := &HostForDevice{} @@ -154,6 +154,10 @@ func (d *DeviceHostConverter) DexJarBuildPath() android.Path { return nil } +func (d *DeviceHostConverter) DexJarInstallPath() android.Path { + return nil +} + func (d *DeviceHostConverter) AidlIncludeDirs() android.Paths { return nil } diff --git a/java/dexpreopt.go b/java/dexpreopt.go index 2911fd9b9..c33415ef6 100644 --- a/java/dexpreopt.go +++ b/java/dexpreopt.go @@ -77,10 +77,6 @@ func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext) bool { return true } - if ctx.Config().UnbundledBuild() { - return true - } - if d.isTest { return true } diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go index 9d9383814..41205598e 100644 --- a/java/dexpreopt_bootjars.go +++ b/java/dexpreopt_bootjars.go @@ -179,15 +179,7 @@ func RegisterDexpreoptBootJarsComponents(ctx android.RegistrationContext) { } func skipDexpreoptBootJars(ctx android.PathContext) bool { - if dexpreopt.GetGlobalConfig(ctx).DisablePreopt { - return true - } - - if ctx.Config().UnbundledBuild() { - return true - } - - return false + return dexpreopt.GetGlobalConfig(ctx).DisablePreopt } type dexpreoptBootJars struct { @@ -340,10 +332,12 @@ func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootI bootFrameworkProfileRule(ctx, image, missingDeps) updatableBcpPackagesRule(ctx, image, missingDeps) - var allFiles android.Paths + var zipFiles android.Paths for _, variant := range image.variants { files := buildBootImageVariant(ctx, variant, profile, missingDeps) - allFiles = append(allFiles, files.Paths()...) + if variant.target.Os == android.Android { + zipFiles = append(zipFiles, files.Paths()...) + } } if image.zip != nil { @@ -351,8 +345,8 @@ func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootI rule.Command(). BuiltTool(ctx, "soong_zip"). FlagWithOutput("-o ", image.zip). - FlagWithArg("-C ", image.dir.String()). - FlagWithInputList("-f ", allFiles, " -f ") + FlagWithArg("-C ", image.dir.Join(ctx, android.Android.String()).String()). + FlagWithInputList("-f ", zipFiles, " -f ") rule.Build(pctx, ctx, "zip_"+image.name, "zip "+image.name+" image") } diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go index e9704dc2a..9670c7f4b 100644 --- a/java/dexpreopt_bootjars_test.go +++ b/java/dexpreopt_bootjars_test.go @@ -118,7 +118,7 @@ func TestDexpreoptBootZip(t *testing.T) { ctx := android.PathContextForTesting(testConfig(nil, "", nil)) expectedInputs := []string{} - for _, target := range dexpreoptTargets(ctx) { + for _, target := range ctx.Config().Targets[android.Android] { for _, ext := range []string{".art", ".oat", ".vdex"} { for _, jar := range []string{"foo", "bar", "baz"} { expectedInputs = append(expectedInputs, diff --git a/java/droiddoc.go b/java/droiddoc.go index 4c3e11236..68cfe9fde 100644 --- a/java/droiddoc.go +++ b/java/droiddoc.go @@ -1470,7 +1470,7 @@ func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersi FlagWithInput("@", srcJarList). FlagWithOutput("--strict-input-files:warn ", android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"violations.txt")) - if implicitsRsp.String() != "" { + if implicitsRsp != nil { cmd.FlagWithArg("--strict-input-files-exempt ", "@"+implicitsRsp.String()) } diff --git a/java/java.go b/java/java.go index af68e56b7..1cdfbf187 100644 --- a/java/java.go +++ b/java/java.go @@ -502,6 +502,7 @@ type Dependency interface { ResourceJars() android.Paths ImplementationAndResourcesJars() android.Paths DexJarBuildPath() android.Path + DexJarInstallPath() android.Path AidlIncludeDirs() android.Paths ExportedSdkLibs() []string ExportedPlugins() (android.Paths, []string) @@ -1749,6 +1750,10 @@ func (j *Module) DexJarBuildPath() android.Path { return j.dexJarFile } +func (j *Module) DexJarInstallPath() android.Path { + return j.installFile +} + func (j *Module) ResourceJars() android.Paths { if j.resourceJar == nil { return nil @@ -2575,6 +2580,10 @@ func (j *Import) DexJarBuildPath() android.Path { return nil } +func (j *Import) DexJarInstallPath() android.Path { + return nil +} + func (j *Import) AidlIncludeDirs() android.Paths { return j.exportAidlIncludeDirs } @@ -2754,8 +2763,10 @@ func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.maybeStrippedDexJarFile = dexOutputFile - ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"), - j.Stem()+".jar", dexOutputFile) + if j.IsForPlatform() { + ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"), + j.Stem()+".jar", dexOutputFile) + } } func (j *DexImport) DexJarBuildPath() android.Path { @@ -2863,11 +2874,7 @@ func (ks *kytheExtractJavaSingleton) GenerateBuildActions(ctx android.SingletonC }) // TODO(asmundak): perhaps emit a rule to output a warning if there were no xrefTargets if len(xrefTargets) > 0 { - ctx.Build(pctx, android.BuildParams{ - Rule: blueprint.Phony, - Output: android.PathForPhony(ctx, "xref_java"), - Inputs: xrefTargets, - }) + ctx.Phony("xref_java", xrefTargets...) } } diff --git a/java/java_test.go b/java/java_test.go index 8ea34d975..215070e6f 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -142,9 +142,14 @@ func testJavaErrorWithConfig(t *testing.T, pattern string, config android.Config return ctx, config } +func testJavaWithFS(t *testing.T, bp string, fs map[string][]byte) (*android.TestContext, android.Config) { + t.Helper() + return testJavaWithConfig(t, testConfig(nil, bp, fs)) +} + func testJava(t *testing.T, bp string) (*android.TestContext, android.Config) { t.Helper() - return testJavaWithConfig(t, testConfig(nil, bp, nil)) + return testJavaWithFS(t, bp, nil) } func testJavaWithConfig(t *testing.T, config android.Config) (*android.TestContext, android.Config) { @@ -740,7 +745,7 @@ func TestResources(t *testing.T) { for _, test := range table { t.Run(test.name, func(t *testing.T) { - ctx, _ := testJava(t, ` + ctx, _ := testJavaWithFS(t, ` java_library { name: "foo", srcs: [ @@ -750,7 +755,13 @@ func TestResources(t *testing.T) { ], `+test.prop+`, } - `+test.extra) + `+test.extra, + map[string][]byte{ + "java-res/a/a": nil, + "java-res/b/b": nil, + "java-res2/a": nil, + }, + ) foo := ctx.ModuleForTests("foo", "android_common").Output("withres/foo.jar") fooRes := ctx.ModuleForTests("foo", "android_common").Output("res/foo.jar") @@ -769,7 +780,7 @@ func TestResources(t *testing.T) { } func TestIncludeSrcs(t *testing.T) { - ctx, _ := testJava(t, ` + ctx, _ := testJavaWithFS(t, ` java_library { name: "foo", srcs: [ @@ -790,7 +801,11 @@ func TestIncludeSrcs(t *testing.T) { java_resource_dirs: ["java-res"], include_srcs: true, } - `) + `, map[string][]byte{ + "java-res/a/a": nil, + "java-res/b/b": nil, + "java-res2/a": nil, + }) // Test a library with include_srcs: true foo := ctx.ModuleForTests("foo", "android_common").Output("withres/foo.jar") @@ -832,7 +847,7 @@ func TestIncludeSrcs(t *testing.T) { } func TestGeneratedSources(t *testing.T) { - ctx, _ := testJava(t, ` + ctx, _ := testJavaWithFS(t, ` java_library { name: "foo", srcs: [ @@ -847,7 +862,10 @@ func TestGeneratedSources(t *testing.T) { tool_files: ["java-res/a"], out: ["gen.java"], } - `) + `, map[string][]byte{ + "a.java": nil, + "b.java": nil, + }) javac := ctx.ModuleForTests("foo", "android_common").Rule("javac") genrule := ctx.ModuleForTests("gen", "").Rule("generator") @@ -932,7 +950,7 @@ func TestSharding(t *testing.T) { } func TestDroiddoc(t *testing.T) { - ctx, _ := testJava(t, ` + ctx, _ := testJavaWithFS(t, ` droiddoc_exported_dir { name: "droiddoc-templates-sdk", path: ".", @@ -945,7 +963,7 @@ func TestDroiddoc(t *testing.T) { droiddoc { name: "bar-doc", srcs: [ - "bar-doc/*.java", + "bar-doc/a.java", "bar-doc/IFoo.aidl", ":bar-doc-aidl-srcs", ], @@ -963,7 +981,11 @@ func TestDroiddoc(t *testing.T) { todo_file: "libcore-docs-todo.html", args: "-offlinemode -title \"libcore\"", } - `) + `, + map[string][]byte{ + "bar-doc/a.java": nil, + "bar-doc/b.java": nil, + }) barDoc := ctx.ModuleForTests("bar-doc", "android_common").Rule("javadoc") var javaSrcs []string @@ -989,7 +1011,7 @@ func TestDroidstubsWithSystemModules(t *testing.T) { droidstubs { name: "stubs-source-system-modules", srcs: [ - "bar-doc/*.java", + "bar-doc/a.java", ], sdk_version: "none", system_modules: "source-system-modules", @@ -1010,7 +1032,7 @@ func TestDroidstubsWithSystemModules(t *testing.T) { droidstubs { name: "stubs-prebuilt-system-modules", srcs: [ - "bar-doc/*.java", + "bar-doc/a.java", ], sdk_version: "none", system_modules: "prebuilt-system-modules", diff --git a/java/testing.go b/java/testing.go index f993f56b3..f34c64af6 100644 --- a/java/testing.go +++ b/java/testing.go @@ -25,35 +25,12 @@ func TestConfig(buildDir string, env map[string]string, bp string, fs map[string bp += GatherRequiredDepsForTest() mockFS := map[string][]byte{ - "a.java": nil, - "b.java": nil, - "c.java": nil, - "b.kt": nil, - "a.jar": nil, - "b.jar": nil, - "c.jar": nil, - "APP_NOTICE": nil, - "GENRULE_NOTICE": nil, - "LIB_NOTICE": nil, - "TOOL_NOTICE": nil, - "AndroidTest.xml": nil, - "java-res/a/a": nil, - "java-res/b/b": nil, - "java-res2/a": nil, - "java-fg/a.java": nil, - "java-fg/b.java": nil, - "java-fg/c.java": nil, "api/current.txt": nil, "api/removed.txt": nil, "api/system-current.txt": nil, "api/system-removed.txt": nil, "api/test-current.txt": nil, "api/test-removed.txt": nil, - "framework/aidl/a.aidl": nil, - "aidl/foo/IFoo.aidl": nil, - "aidl/bar/IBar.aidl": nil, - "assets_a/a": nil, - "assets_b/b": nil, "prebuilts/sdk/14/public/android.jar": nil, "prebuilts/sdk/14/public/framework.aidl": nil, @@ -103,45 +80,6 @@ func TestConfig(buildDir string, env map[string]string, bp string, fs map[string "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"],}`), - - "prebuilts/apk/app.apk": nil, - "prebuilts/apk/app_arm.apk": nil, - "prebuilts/apk/app_arm64.apk": nil, - "prebuilts/apk/app_xhdpi.apk": nil, - "prebuilts/apk/app_xxhdpi.apk": nil, - - "prebuilts/apks/app.apks": nil, - - // For framework-res, which is an implicit dependency for framework - "AndroidManifest.xml": nil, - "build/make/target/product/security/testkey": nil, - - "build/soong/scripts/jar-wrapper.sh": nil, - - "build/make/core/verify_uses_libraries.sh": nil, - - "build/make/core/proguard.flags": nil, - "build/make/core/proguard_basic_keeps.flags": nil, - - "jdk8/jre/lib/jce.jar": nil, - "jdk8/jre/lib/rt.jar": nil, - "jdk8/lib/tools.jar": nil, - - "bar-doc/a.java": nil, - "bar-doc/b.java": nil, - "bar-doc/IFoo.aidl": nil, - "bar-doc/IBar.aidl": nil, - "bar-doc/known_oj_tags.txt": nil, - "external/doclava/templates-sdk": nil, - - "cert/new_cert.x509.pem": nil, - "cert/new_cert.pk8": nil, - "lineage.bin": nil, - - "testdata/data": nil, - - "stubs-sources/foo/Foo.java": nil, - "stubs/sources/foo/Foo.java": nil, } cc.GatherRequiredFilesForTest(mockFS) diff --git a/python/androidmk.go b/python/androidmk.go index d293d52a1..247b80dc0 100644 --- a/python/androidmk.go +++ b/python/androidmk.go @@ -66,15 +66,9 @@ func (p *testDecorator) AndroidMk(base *Module, ret *android.AndroidMkData) { fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE :=", strings.Join(p.binaryDecorator.binaryProperties.Test_suites, " ")) } - // If the test config has an explicit config specified use it. - if p.testProperties.Test_config != nil { - fmt.Fprintln(w, "LOCAL_TEST_CONFIG :=", - *p.testProperties.Test_config) - } else { - if p.testConfig != nil { - fmt.Fprintln(w, "LOCAL_FULL_TEST_CONFIG :=", - p.testConfig.String()) - } + if p.testConfig != nil { + fmt.Fprintln(w, "LOCAL_FULL_TEST_CONFIG :=", + p.testConfig.String()) } if !BoolDefault(p.binaryProperties.Auto_gen_config, true) { diff --git a/python/test.go b/python/test.go index f684fd51d..a669c73a6 100644 --- a/python/test.go +++ b/python/test.go @@ -29,11 +29,11 @@ func init() { type TestProperties struct { // the name of the test configuration (for example "AndroidTest.xml") that should be // installed with the module. - Test_config *string `android:"arch_variant"` + Test_config *string `android:"path,arch_variant"` // the name of the test configuration template (for example "AndroidTestTemplate.xml") that // should be installed with the module. - Test_config_template *string `android:"arch_variant"` + Test_config_template *string `android:"path,arch_variant"` } type testDecorator struct { diff --git a/rust/Android.bp b/rust/Android.bp index 684db0bdd..b06ea8e75 100644 --- a/rust/Android.bp +++ b/rust/Android.bp @@ -16,6 +16,7 @@ bootstrap_go_package { "library.go", "prebuilt.go", "proc_macro.go", + "project_json.go", "rust.go", "test.go", "testing.go", @@ -25,6 +26,7 @@ bootstrap_go_package { "compiler_test.go", "coverage_test.go", "library_test.go", + "project_json_test.go", "rust_test.go", "test_test.go", ], diff --git a/rust/OWNERS b/rust/OWNERS index 82713f996..afd06e422 100644 --- a/rust/OWNERS +++ b/rust/OWNERS @@ -1,5 +1,5 @@ # Additional owner/reviewers for rust rules, including parent directory owners. per-file * = chh@google.com, ivanlozano@google.com, jeffv@google.com, srhines@google.com -# Limited owners/reviewers of the whitelist. -per-file whitelist.go = chh@google.com, ivanlozano@google.com, jeffv@google.com, jgalenson@google.com, srhines@google.com +# Limited owners/reviewers of the allowed list. +per-file allowed_list.go = chh@google.com, ivanlozano@google.com, jeffv@google.com, jgalenson@google.com, srhines@google.com diff --git a/rust/config/Android.bp b/rust/config/Android.bp index 1a10312e2..5026da39e 100644 --- a/rust/config/Android.bp +++ b/rust/config/Android.bp @@ -10,7 +10,7 @@ bootstrap_go_package { "arm64_device.go", "global.go", "toolchain.go", - "whitelist.go", + "allowed_list.go", "x86_darwin_host.go", "x86_linux_host.go", "x86_device.go", diff --git a/rust/config/whitelist.go b/rust/config/allowed_list.go index a339050f8..a339050f8 100644 --- a/rust/config/whitelist.go +++ b/rust/config/allowed_list.go diff --git a/rust/library.go b/rust/library.go index 8aa033c0f..2e5126639 100644 --- a/rust/library.go +++ b/rust/library.go @@ -329,12 +329,21 @@ func (library *libraryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps { return deps } + +func (library *libraryDecorator) sharedLibFilename(ctx ModuleContext) string { + return library.getStem(ctx) + ctx.toolchain().SharedLibSuffix() +} + func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags { flags.RustFlags = append(flags.RustFlags, "-C metadata="+ctx.baseModuleName()) flags = library.baseCompiler.compilerFlags(ctx, flags) if library.shared() || library.static() { library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Include_dirs)...) } + if library.shared() { + flags.LinkFlags = append(flags.LinkFlags, "-Wl,-soname="+library.sharedLibFilename(ctx)) + } + return flags } @@ -371,7 +380,7 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa outputs := TransformSrctoStatic(ctx, srcPath, deps, flags, outputFile, deps.linkDirs) library.coverageFile = outputs.coverageFile } else if library.shared() { - fileName := library.getStem(ctx) + ctx.toolchain().SharedLibSuffix() + fileName := library.sharedLibFilename(ctx) outputFile = android.PathForModuleOut(ctx, fileName) outputs := TransformSrctoShared(ctx, srcPath, deps, flags, outputFile, deps.linkDirs) diff --git a/rust/library_test.go b/rust/library_test.go index 9f9f374b9..37dd5414c 100644 --- a/rust/library_test.go +++ b/rust/library_test.go @@ -114,3 +114,17 @@ func TestValidateLibraryStem(t *testing.T) { }`) } + +func TestSharedLibraryFlags(t *testing.T) { + ctx := testRust(t, ` + rust_library_host { + 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"]) + } +} diff --git a/rust/project_json.go b/rust/project_json.go new file mode 100644 index 000000000..909aebc98 --- /dev/null +++ b/rust/project_json.go @@ -0,0 +1,161 @@ +// 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 rust + +import ( + "encoding/json" + "fmt" + "path" + + "android/soong/android" +) + +// This singleton collects Rust crate definitions and generates a JSON file +// (${OUT_DIR}/soong/rust-project.json) which can be use by external tools, +// such as rust-analyzer. It does so when either make, mm, mma, mmm or mmma is +// called. This singleton is enabled only if SOONG_GEN_RUST_PROJECT is set. +// For example, +// +// $ SOONG_GEN_RUST_PROJECT=1 m nothing + +func init() { + android.RegisterSingletonType("rust_project_generator", rustProjectGeneratorSingleton) +} + +func rustProjectGeneratorSingleton() android.Singleton { + return &projectGeneratorSingleton{} +} + +type projectGeneratorSingleton struct{} + +const ( + // Environment variables used to control the behavior of this singleton. + envVariableCollectRustDeps = "SOONG_GEN_RUST_PROJECT" + rustProjectJsonFileName = "rust-project.json" +) + +// The format of rust-project.json is not yet finalized. A current description is available at: +// https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/user/manual.adoc#non-cargo-based-projects +type rustProjectDep struct { + Crate int `json:"crate"` + Name string `json:"name"` +} + +type rustProjectCrate struct { + RootModule string `json:"root_module"` + Edition string `json:"edition,omitempty"` + Deps []rustProjectDep `json:"deps"` + Cfgs []string `json:"cfgs"` +} + +type rustProjectJson struct { + Roots []string `json:"roots"` + Crates []rustProjectCrate `json:"crates"` +} + +// crateInfo is used during the processing to keep track of the known crates. +type crateInfo struct { + ID int + Deps map[string]int +} + +func mergeDependencies(ctx android.SingletonContext, project *rustProjectJson, + knownCrates map[string]crateInfo, module android.Module, + crate *rustProjectCrate, deps map[string]int) { + + //TODO(tweek): The stdlib dependencies do not appear here. We need to manually add them. + ctx.VisitDirectDeps(module, func(child android.Module) { + childId, childName, ok := appendLibraryAndDeps(ctx, project, knownCrates, child) + if !ok { + return + } + if _, ok = deps[childName]; ok { + return + } + crate.Deps = append(crate.Deps, rustProjectDep{Crate: childId, Name: childName}) + deps[childName] = childId + }) +} + +// appendLibraryAndDeps creates a rustProjectCrate for the module argument and +// appends it to the rustProjectJson struct. It visits the dependencies of the +// module depth-first. If the current module is already in knownCrates, its +// its dependencies are merged. Returns a tuple (id, crate_name, ok). +func appendLibraryAndDeps(ctx android.SingletonContext, project *rustProjectJson, + knownCrates map[string]crateInfo, module android.Module) (int, string, bool) { + rModule, ok := module.(*Module) + if !ok { + return 0, "", false + } + if rModule.compiler == nil { + return 0, "", false + } + rustLib, ok := rModule.compiler.(*libraryDecorator) + if !ok { + return 0, "", false + } + crateName := rModule.CrateName() + if cInfo, ok := knownCrates[crateName]; ok { + // We have seen this crate already; merge any new dependencies. + crate := project.Crates[cInfo.ID] + mergeDependencies(ctx, project, knownCrates, module, &crate, cInfo.Deps) + return cInfo.ID, crateName, true + } + crate := rustProjectCrate{Deps: make([]rustProjectDep, 0), Cfgs: make([]string, 0)} + src := rustLib.Properties.Srcs[0] + crate.RootModule = path.Join(ctx.ModuleDir(rModule), src) + crate.Edition = getEdition(rustLib.baseCompiler) + + deps := make(map[string]int) + mergeDependencies(ctx, project, knownCrates, module, &crate, deps) + + id := len(project.Crates) + knownCrates[crateName] = crateInfo{ID: id, Deps: deps} + project.Crates = append(project.Crates, crate) + // rust-analyzer requires that all crates belong to at least one root: + // https://github.com/rust-analyzer/rust-analyzer/issues/4735. + project.Roots = append(project.Roots, path.Dir(crate.RootModule)) + return id, crateName, true +} + +func (r *projectGeneratorSingleton) GenerateBuildActions(ctx android.SingletonContext) { + if !ctx.Config().IsEnvTrue(envVariableCollectRustDeps) { + return + } + + project := rustProjectJson{} + knownCrates := make(map[string]crateInfo) + ctx.VisitAllModules(func(module android.Module) { + appendLibraryAndDeps(ctx, &project, knownCrates, module) + }) + + path := android.PathForOutput(ctx, rustProjectJsonFileName) + err := createJsonFile(project, path) + if err != nil { + ctx.Errorf(err.Error()) + } +} + +func createJsonFile(project rustProjectJson, rustProjectPath android.WritablePath) error { + buf, err := json.MarshalIndent(project, "", " ") + if err != nil { + return fmt.Errorf("JSON marshal of rustProjectJson failed: %s", err) + } + err = android.WriteFileToOutputDir(rustProjectPath, buf, 0666) + if err != nil { + return fmt.Errorf("Writing rust-project to %s failed: %s", rustProjectPath.String(), err) + } + return nil +} diff --git a/rust/project_json_test.go b/rust/project_json_test.go new file mode 100644 index 000000000..6786e72c7 --- /dev/null +++ b/rust/project_json_test.go @@ -0,0 +1,55 @@ +// 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 rust + +import ( + "io/ioutil" + "path/filepath" + "testing" + + "android/soong/android" + "android/soong/cc" +) + +func TestProjectJson(t *testing.T) { + bp := `rust_library { + name: "liba", + srcs: ["src/lib.rs"], + crate_name: "a" + }` + GatherRequiredDepsForTest() + env := map[string]string{"SOONG_GEN_RUST_PROJECT": "1"} + fs := map[string][]byte{ + "foo.rs": nil, + "src/lib.rs": nil, + } + + cc.GatherRequiredFilesForTest(fs) + + config := android.TestArchConfig(buildDir, env, bp, fs) + ctx := CreateTestContext() + ctx.Register(config) + _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) + android.FailIfErrored(t, errs) + _, errs = ctx.PrepareBuildActions(config) + android.FailIfErrored(t, errs) + + // The JSON file is generated via WriteFileToOutputDir. Therefore, it + // won't appear in the Output of the TestingSingleton. Manually verify + // it exists. + _, err := ioutil.ReadFile(filepath.Join(buildDir, "rust-project.json")) + if err != nil { + t.Errorf("rust-project.json has not been generated") + } +} diff --git a/rust/test.go b/rust/test.go index 94568c1cc..10c278597 100644 --- a/rust/test.go +++ b/rust/test.go @@ -25,11 +25,11 @@ import ( type TestProperties struct { // the name of the test configuration (for example "AndroidTest.xml") that should be // installed with the module. - Test_config *string `android:"arch_variant"` + Test_config *string `android:"path,arch_variant"` // the name of the test configuration template (for example "AndroidTestTemplate.xml") that // should be installed with the module. - Test_config_template *string `android:"arch_variant"` + Test_config_template *string `android:"path,arch_variant"` // list of compatibility suites (for example "cts", "vts") that the module should be // installed into. diff --git a/rust/testing.go b/rust/testing.go index 09008a85f..f94af71ee 100644 --- a/rust/testing.go +++ b/rust/testing.go @@ -100,6 +100,7 @@ func CreateTestContext() *android.TestContext { ctx.BottomUp("rust_unit_tests", TestPerSrcMutator).Parallel() ctx.BottomUp("rust_begin", BeginMutator).Parallel() }) + ctx.RegisterSingletonType("rust_project_generator", rustProjectGeneratorSingleton) return ctx } diff --git a/scripts/build-mainline-modules.sh b/scripts/build-mainline-modules.sh index f836ea9fa..df763c822 100755 --- a/scripts/build-mainline-modules.sh +++ b/scripts/build-mainline-modules.sh @@ -20,6 +20,7 @@ MODULES_SDK_AND_EXPORTS=( conscrypt-module-test-exports conscrypt-module-host-exports runtime-module-sdk + runtime-module-host-exports ) # We want to create apex modules for all supported architectures. diff --git a/sdk/update.go b/sdk/update.go index 1ba58064d..824115138 100644 --- a/sdk/update.go +++ b/sdk/update.go @@ -22,6 +22,7 @@ import ( "android/soong/apex" "android/soong/cc" + "github.com/google/blueprint" "github.com/google/blueprint/proptools" @@ -700,8 +701,8 @@ func (s *snapshotBuilder) AddPrebuiltModule(member android.SdkMember, moduleType if apexAware, ok := variant.(interface{ ApexAvailable() []string }); ok { apexAvailable := apexAware.ApexAvailable() - // Add in any white listed apex available settings. - apexAvailable = append(apexAvailable, apex.WhitelistedApexAvailable(member.Name())...) + // Add in any baseline apex available settings. + apexAvailable = append(apexAvailable, apex.BaselineApexAvailable(member.Name())...) if len(apexAvailable) > 0 { // Remove duplicates and sort. diff --git a/sh/sh_binary.go b/sh/sh_binary.go index 9276a62e9..7bb267da2 100644 --- a/sh/sh_binary.go +++ b/sh/sh_binary.go @@ -70,7 +70,7 @@ type TestProperties struct { // the name of the test configuration (for example "AndroidTest.xml") that should be // installed with the module. - Test_config *string `android:"arch_variant"` + Test_config *string `android:"path,arch_variant"` // list of files or filegroup modules that provide data that should be installed alongside // the test. @@ -231,12 +231,8 @@ func (s *ShTest) AndroidMkEntries() []android.AndroidMkEntries { s.customAndroidMkEntries(entries) entries.AddStrings("LOCAL_COMPATIBILITY_SUITE", s.testProperties.Test_suites...) - if s.testProperties.Test_config != nil { - entries.SetString("LOCAL_TEST_CONFIG", proptools.String(s.testProperties.Test_config)) - } else { - if s.testConfig != nil { - entries.SetString("LOCAL_FULL_TEST_CONFIG", s.testConfig.String()) - } + if s.testConfig != nil { + entries.SetPath("LOCAL_FULL_TEST_CONFIG", s.testConfig) } for _, d := range s.data { rel := d.Rel() @@ -260,9 +256,6 @@ func InitShBinaryModule(s *ShBinary) { // executable binary to <partition>/bin. func ShBinaryFactory() android.Module { module := &ShBinary{} - module.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase, class android.OsClass) bool { - return class == android.Device && ctx.Config().DevicePrefer32BitExecutables() - }) InitShBinaryModule(module) android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibFirst) return module diff --git a/ui/build/config.go b/ui/build/config.go index 49f506ef9..c4bbad76f 100644 --- a/ui/build/config.go +++ b/ui/build/config.go @@ -592,6 +592,7 @@ func (c *configImpl) Lunch(ctx Context, product, variant string) { c.environ.Set("TARGET_BUILD_VARIANT", variant) c.environ.Set("TARGET_BUILD_TYPE", "release") c.environ.Unset("TARGET_BUILD_APPS") + c.environ.Unset("TARGET_BUILD_UNBUNDLED") } // Tapas configures the environment to build one or more unbundled apps, diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go index 7dc4915e2..e22985675 100644 --- a/ui/build/dumpvars.go +++ b/ui/build/dumpvars.go @@ -143,6 +143,7 @@ var BannerVars = []string{ "TARGET_BUILD_VARIANT", "TARGET_BUILD_TYPE", "TARGET_BUILD_APPS", + "TARGET_BUILD_UNBUNDLED", "TARGET_ARCH", "TARGET_ARCH_VARIANT", "TARGET_CPU_VARIANT", @@ -187,6 +188,7 @@ func runMakeProductConfig(ctx Context, config Config) { "TARGET_PRODUCT", "TARGET_BUILD_VARIANT", "TARGET_BUILD_APPS", + "TARGET_BUILD_UNBUNDLED", // compiler wrappers set up by make "CC_WRAPPER", |