diff options
| -rw-r--r-- | android/arch.go | 2 | ||||
| -rw-r--r-- | android/makevars.go | 2 | ||||
| -rw-r--r-- | android/module.go | 14 | ||||
| -rw-r--r-- | android/prebuilt.go | 2 | ||||
| -rw-r--r-- | cc/config/Android.bp | 2 | ||||
| -rw-r--r-- | cc/config/arm64_linux_host.go | 94 | ||||
| -rw-r--r-- | cc/prebuilt.go | 66 | ||||
| -rw-r--r-- | cc/prebuilt_test.go | 50 | ||||
| -rw-r--r-- | cc/vendor_snapshot.go | 5 | ||||
| -rw-r--r-- | cmd/soong_build/bazel_overlay.go | 305 | ||||
| -rw-r--r-- | cmd/soong_build/bazel_overlay_test.go | 209 | ||||
| -rw-r--r-- | cmd/soong_build/writedocs.go | 7 | ||||
| -rw-r--r-- | dexpreopt/config.go | 67 | ||||
| -rw-r--r-- | java/Android.bp | 1 | ||||
| -rw-r--r-- | java/android_manifest.go | 12 | ||||
| -rwxr-xr-x | java/app.go | 38 | ||||
| -rw-r--r-- | java/droiddoc.go | 16 | ||||
| -rw-r--r-- | java/hiddenapi_singleton.go | 1 | ||||
| -rw-r--r-- | java/hiddenapi_singleton_test.go | 136 | ||||
| -rw-r--r-- | java/java.go | 11 | ||||
| -rw-r--r-- | java/testing.go | 1 | ||||
| -rw-r--r-- | rust/compiler.go | 4 | ||||
| -rw-r--r-- | rust/config/Android.bp | 1 | ||||
| -rw-r--r-- | rust/config/arm64_device.go | 9 | ||||
| -rw-r--r-- | rust/config/arm64_linux_host.go | 24 | ||||
| -rw-r--r-- | rust/rust.go | 15 |
26 files changed, 925 insertions, 169 deletions
diff --git a/android/arch.go b/android/arch.go index ba113b2b5..d055a6fe0 100644 --- a/android/arch.go +++ b/android/arch.go @@ -579,7 +579,7 @@ var ( osArchTypeMap = map[OsType][]ArchType{ Linux: []ArchType{X86, X86_64}, - LinuxBionic: []ArchType{X86_64}, + LinuxBionic: []ArchType{Arm64, X86_64}, Darwin: []ArchType{X86_64}, Windows: []ArchType{X86, X86_64}, Android: []ArchType{Arm, Arm64, X86, X86_64}, diff --git a/android/makevars.go b/android/makevars.go index 86f4b424b..003a9df32 100644 --- a/android/makevars.go +++ b/android/makevars.go @@ -234,7 +234,7 @@ func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) { } ctx.VisitAllModules(func(m Module) { - if provider, ok := m.(ModuleMakeVarsProvider); ok { + if provider, ok := m.(ModuleMakeVarsProvider); ok && m.Enabled() { mctx := &makeVarsContext{ SingletonContext: ctx, } diff --git a/android/module.go b/android/module.go index bfb87fa75..337ae4076 100644 --- a/android/module.go +++ b/android/module.go @@ -259,6 +259,8 @@ type Module interface { SkipInstall() IsSkipInstall() bool MakeUninstallable() + ReplacedByPrebuilt() + IsReplacedByPrebuilt() bool ExportedToMake() bool InitRc() Paths VintfFragments() Paths @@ -543,6 +545,9 @@ type commonProperties struct { SkipInstall bool `blueprint:"mutated"` + // Whether the module has been replaced by a prebuilt + ReplacedByPrebuilt bool `blueprint:"mutated"` + // Disabled by mutators. If set to true, it overrides Enabled property. ForcedDisabled bool `blueprint:"mutated"` @@ -1068,6 +1073,15 @@ func (m *ModuleBase) MakeUninstallable() { m.SkipInstall() } +func (m *ModuleBase) ReplacedByPrebuilt() { + m.commonProperties.ReplacedByPrebuilt = true + m.SkipInstall() +} + +func (m *ModuleBase) IsReplacedByPrebuilt() bool { + return m.commonProperties.ReplacedByPrebuilt +} + func (m *ModuleBase) ExportedToMake() bool { return m.commonProperties.NamespaceExportedToMake } diff --git a/android/prebuilt.go b/android/prebuilt.go index 269ad5d8a..734871b6b 100644 --- a/android/prebuilt.go +++ b/android/prebuilt.go @@ -253,7 +253,7 @@ func PrebuiltSelectModuleMutator(ctx TopDownMutatorContext) { p := m.(PrebuiltInterface).Prebuilt() if p.usePrebuilt(ctx, s) { p.properties.UsePrebuilt = true - s.SkipInstall() + s.ReplacedByPrebuilt() } }) } diff --git a/cc/config/Android.bp b/cc/config/Android.bp index 6275064f5..ce4bdfb50 100644 --- a/cc/config/Android.bp +++ b/cc/config/Android.bp @@ -23,6 +23,8 @@ bootstrap_go_package { "x86_linux_host.go", "x86_linux_bionic_host.go", "x86_windows_host.go", + + "arm64_linux_host.go", ], testSrcs: [ "tidy_test.go", diff --git a/cc/config/arm64_linux_host.go b/cc/config/arm64_linux_host.go new file mode 100644 index 000000000..74642c2cf --- /dev/null +++ b/cc/config/arm64_linux_host.go @@ -0,0 +1,94 @@ +// 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 config + +import ( + "android/soong/android" + "strings" +) + +var ( + // This is a host toolchain but flags for device toolchain are required + // as the flags are actually for Bionic-based builds. + linuxCrossCflags = ClangFilterUnknownCflags(append(deviceGlobalCflags, + // clang by default enables PIC when the clang triple is set to *-android. + // See toolchain/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.cpp#920. + // However, for this host target, we don't set "-android" to avoid __ANDROID__ macro + // which stands for "Android device target". Keeping PIC on is required because + // many modules we have (e.g. Bionic) assume PIC. + "-fpic", + )) + + linuxCrossLdflags = ClangFilterUnknownCflags([]string{ + "-Wl,-z,noexecstack", + "-Wl,-z,relro", + "-Wl,-z,now", + "-Wl,--build-id=md5", + "-Wl,--warn-shared-textrel", + "-Wl,--fatal-warnings", + "-Wl,--hash-style=gnu", + "-Wl,--no-undefined-version", + }) +) + +func init() { + pctx.StaticVariable("LinuxBionicArm64Cflags", strings.Join(linuxCrossCflags, " ")) + pctx.StaticVariable("LinuxBionicArm64Ldflags", strings.Join(linuxCrossLdflags, " ")) +} + +// toolchain config for ARM64 Linux CrossHost. Almost everything is the same as the ARM64 Android +// target. The overridden methods below show the differences. +type toolchainLinuxArm64 struct { + toolchainArm64 +} + +func (toolchainLinuxArm64) ClangTriple() string { + // Note the absence of "-android" suffix. The compiler won't define __ANDROID__ + return "aarch64-linux" +} + +func (toolchainLinuxArm64) ClangCflags() string { + // The inherited flags + extra flags + return "${config.Arm64ClangCflags} ${config.LinuxBionicArm64Cflags}" +} + +func linuxArm64ToolchainFactory(arch android.Arch) Toolchain { + archVariant := "armv8-a" // for host, default to armv8-a + toolchainClangCflags := []string{arm64ClangArchVariantCflagsVar[archVariant]} + + // We don't specify CPU architecture for host. Conservatively assume + // the host CPU needs the fix + extraLdflags := "-Wl,--fix-cortex-a53-843419" + + ret := toolchainLinuxArm64{} + + // add the extra ld and lld flags + ret.toolchainArm64.ldflags = strings.Join([]string{ + "${config.Arm64Ldflags}", + "${config.LinuxBionicArm64Ldflags}", + extraLdflags, + }, " ") + ret.toolchainArm64.lldflags = strings.Join([]string{ + "${config.Arm64Lldflags}", + "${config.LinuxBionicArm64Ldflags}", + extraLdflags, + }, " ") + ret.toolchainArm64.toolchainClangCflags = strings.Join(toolchainClangCflags, " ") + return &ret +} + +func init() { + registerToolchainFactory(android.LinuxBionic, android.Arm64, linuxArm64ToolchainFactory) +} diff --git a/cc/prebuilt.go b/cc/prebuilt.go index 3af65d654..1ee096e18 100644 --- a/cc/prebuilt.go +++ b/cc/prebuilt.go @@ -324,35 +324,68 @@ func prebuiltObjectFactory() android.Module { type prebuiltBinaryLinker struct { *binaryDecorator prebuiltLinker + + toolPath android.OptionalPath } var _ prebuiltLinkerInterface = (*prebuiltBinaryLinker)(nil) +func (p *prebuiltBinaryLinker) hostToolPath() android.OptionalPath { + return p.toolPath +} + func (p *prebuiltBinaryLinker) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path { // TODO(ccross): verify shared library dependencies if len(p.properties.Srcs) > 0 { - stripFlags := flagsToStripFlags(flags) - fileName := p.getStem(ctx) + flags.Toolchain.ExecutableSuffix() in := p.Prebuilt.SingleSourcePath(ctx) - + outputFile := android.PathForModuleOut(ctx, fileName) p.unstrippedOutputFile = in - if p.stripper.NeedsStrip(ctx) { - stripped := android.PathForModuleOut(ctx, "stripped", fileName) - p.stripper.StripExecutableOrSharedLib(ctx, in, stripped, stripFlags) - in = stripped - } + if ctx.Host() { + // Host binaries are symlinked to their prebuilt source locations. That + // way they are executed directly from there so the linker resolves their + // shared library dependencies relative to that location (using + // $ORIGIN/../lib(64):$ORIGIN/lib(64) as RUNPATH). This way the prebuilt + // repository can supply the expected versions of the shared libraries + // without interference from what is in the out tree. + + // These shared lib paths may point to copies of the libs in + // .intermediates, which isn't where the binary will load them from, but + // it's fine for dependency tracking. If a library dependency is updated, + // the symlink will get a new timestamp, along with any installed symlinks + // handled in make. + sharedLibPaths := deps.EarlySharedLibs + sharedLibPaths = append(sharedLibPaths, deps.SharedLibs...) + sharedLibPaths = append(sharedLibPaths, deps.LateSharedLibs...) - // Copy binaries to a name matching the final installed name - outputFile := android.PathForModuleOut(ctx, fileName) - ctx.Build(pctx, android.BuildParams{ - Rule: android.CpExecutable, - Description: "prebuilt", - Output: outputFile, - Input: in, - }) + ctx.Build(pctx, android.BuildParams{ + Rule: android.Symlink, + Output: outputFile, + Input: in, + Implicits: sharedLibPaths, + Args: map[string]string{ + "fromPath": "$$PWD/" + in.String(), + }, + }) + + p.toolPath = android.OptionalPathForPath(outputFile) + } else { + if p.stripper.NeedsStrip(ctx) { + stripped := android.PathForModuleOut(ctx, "stripped", fileName) + p.stripper.StripExecutableOrSharedLib(ctx, in, stripped, flagsToStripFlags(flags)) + in = stripped + } + + // Copy binaries to a name matching the final installed name + ctx.Build(pctx, android.BuildParams{ + Rule: android.CpExecutable, + Description: "prebuilt", + Output: outputFile, + Input: in, + }) + } return outputFile } @@ -379,6 +412,7 @@ func NewPrebuiltBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecor binaryDecorator: binary, } module.linker = prebuilt + module.installer = prebuilt module.AddProperties(&prebuilt.properties) diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go index adb44bd71..52416ac3b 100644 --- a/cc/prebuilt_test.go +++ b/cc/prebuilt_test.go @@ -15,6 +15,7 @@ package cc import ( + "path/filepath" "testing" "android/soong/android" @@ -271,3 +272,52 @@ func TestPrebuiltLibrarySharedStem(t *testing.T) { shared := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module().(*Module) assertString(t, shared.OutputFile().Path().Base(), "libbar.so") } + +func TestPrebuiltSymlinkedHostBinary(t *testing.T) { + if android.BuildOs != android.Linux { + t.Skipf("Skipping host prebuilt testing that is only supported on %s not %s", android.Linux, android.BuildOs) + } + + ctx := testPrebuilt(t, ` + cc_prebuilt_library_shared { + name: "libfoo", + device_supported: false, + host_supported: true, + target: { + linux_glibc_x86_64: { + srcs: ["linux_glibc_x86_64/lib64/libfoo.so"], + }, + }, + } + + cc_prebuilt_binary { + name: "foo", + device_supported: false, + host_supported: true, + shared_libs: ["libfoo"], + target: { + linux_glibc_x86_64: { + srcs: ["linux_glibc_x86_64/bin/foo"], + }, + }, + } + `, map[string][]byte{ + "libfoo.so": nil, + "foo": nil, + }) + + fooRule := ctx.ModuleForTests("foo", "linux_glibc_x86_64").Rule("Symlink") + assertString(t, fooRule.Output.String(), + filepath.Join(buildDir, ".intermediates/foo/linux_glibc_x86_64/foo")) + assertString(t, fooRule.Args["fromPath"], "$$PWD/linux_glibc_x86_64/bin/foo") + + var libfooDep android.Path + for _, dep := range fooRule.Implicits { + if dep.Base() == "libfoo.so" { + libfooDep = dep + break + } + } + assertString(t, libfooDep.String(), + filepath.Join(buildDir, ".intermediates/libfoo/linux_glibc_x86_64_shared/libfoo.so")) +} diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go index 0219b847d..2819f4958 100644 --- a/cc/vendor_snapshot.go +++ b/cc/vendor_snapshot.go @@ -541,6 +541,11 @@ func isVendorSnapshotModule(m *Module, inVendorProprietaryPath bool) bool { if !m.Enabled() || m.Properties.HideFromMake { return false } + // When android/prebuilt.go selects between source and prebuilt, it sets + // SkipInstall on the other one to avoid duplicate install rules in make. + if m.IsSkipInstall() { + return false + } // skip proprietary modules, but include all VNDK (static) if inVendorProprietaryPath && !m.IsVndk() { return false diff --git a/cmd/soong_build/bazel_overlay.go b/cmd/soong_build/bazel_overlay.go index 308076d52..72e0fbdf5 100644 --- a/cmd/soong_build/bazel_overlay.go +++ b/cmd/soong_build/bazel_overlay.go @@ -24,16 +24,19 @@ import ( "strings" "github.com/google/blueprint" + "github.com/google/blueprint/bootstrap/bpdoc" "github.com/google/blueprint/proptools" ) const ( + // The default `load` preamble for every generated BUILD file. soongModuleLoad = `package(default_visibility = ["//visibility:public"]) load("//:soong_module.bzl", "soong_module") ` - // A BUILD file target snippet representing a Soong module + // A macro call in the BUILD file representing a Soong module, with space + // for expanding more attributes. soongModuleTarget = `soong_module( name = "%s", module_name = "%s", @@ -42,24 +45,24 @@ load("//:soong_module.bzl", "soong_module") module_deps = %s, %s)` - // The soong_module rule implementation in a .bzl file - soongModuleBzl = `SoongModuleInfo = provider( + // A simple provider to mark and differentiate Soong module rule shims from + // regular Bazel rules. Every Soong module rule shim returns a + // SoongModuleInfo provider, and can only depend on rules returning + // SoongModuleInfo in the `module_deps` attribute. + providersBzl = `SoongModuleInfo = provider( fields = { "name": "Name of module", "type": "Type of module", "variant": "Variant of module", }, ) +` -def _merge_dicts(*dicts): - """Adds a list of dictionaries into a single dictionary.""" - - # If keys are repeated in multiple dictionaries, the latter one "wins". - result = {} - for d in dicts: - result.update(d) + // The soong_module rule implementation in a .bzl file. + soongModuleBzl = ` +%s - return result +load(":providers.bzl", "SoongModuleInfo") def _generic_soong_module_impl(ctx): return [ @@ -70,37 +73,31 @@ def _generic_soong_module_impl(ctx): ), ] -_COMMON_ATTRS = { - "module_name": attr.string(mandatory = True), - "module_type": attr.string(mandatory = True), - "module_variant": attr.string(), - "module_deps": attr.label_list(providers = [SoongModuleInfo]), -} - - generic_soong_module = rule( implementation = _generic_soong_module_impl, - attrs = _COMMON_ATTRS, -) - -# TODO(jingwen): auto generate Soong module shims -def _soong_filegroup_impl(ctx): - return [SoongModuleInfo(),] - -soong_filegroup = rule( - implementation = _soong_filegroup_impl, - # Matches https://cs.android.com/android/platform/superproject/+/master:build/soong/android/filegroup.go;l=25-40;drc=6a6478d49e78703ba22a432c41d819c8df79ef6c - attrs = _merge_dicts(_COMMON_ATTRS, { - "srcs": attr.string_list(doc = "srcs lists files that will be included in this filegroup"), - "exclude_srcs": attr.string_list(), - "path": attr.string(doc = "The base path to the files. May be used by other modules to determine which portion of the path to use. For example, when a filegroup is used as data in a cc_test rule, the base path is stripped off the path and the remaining path is used as the installation directory."), - "export_to_make_var": attr.string(doc = "Create a make variable with the specified name that contains the list of files in the filegroup, relative to the root of the source tree."), - }) + attrs = { + "module_name": attr.string(mandatory = True), + "module_type": attr.string(mandatory = True), + "module_variant": attr.string(), + "module_deps": attr.label_list(providers = [SoongModuleInfo]), + }, ) soong_module_rule_map = { - "filegroup": soong_filegroup, -} +%s} + +_SUPPORTED_TYPES = ["bool", "int", "string"] + +def _is_supported_type(value): + if type(value) in _SUPPORTED_TYPES: + return True + elif type(value) == "list": + supported = True + for v in value: + supported = supported and type(v) in _SUPPORTED_TYPES + return supported + else: + return False # soong_module is a macro that supports arbitrary kwargs, and uses module_type to # expand to the right underlying shim. @@ -118,12 +115,76 @@ def soong_module(name, module_type, **kwargs): module_deps = kwargs.pop("module_deps", []), ) else: + supported_kwargs = dict() + for key, value in kwargs.items(): + if _is_supported_type(value): + supported_kwargs[key] = value soong_module_rule( name = name, - module_type = module_type, - **kwargs, + **supported_kwargs, ) ` + + // A rule shim for representing a Soong module type and its properties. + moduleRuleShim = ` +def _%[1]s_impl(ctx): + return [SoongModuleInfo()] + +%[1]s = rule( + implementation = _%[1]s_impl, + attrs = %[2]s +) +` +) + +var ( + // An allowlist of prop types that are surfaced from module props to rule + // attributes. (nested) dictionaries are notably absent here, because while + // Soong supports multi value typed and nested dictionaries, Bazel's rule + // attr() API supports only single-level string_dicts. + allowedPropTypes = map[string]bool{ + "int": true, // e.g. 42 + "bool": true, // e.g. True + "string_list": true, // e.g. ["a", "b"] + "string": true, // e.g. "a" + } + + // TODO(b/166563303): Specific properties of some module types aren't + // recognized by the documentation generator. As a workaround, hardcode a + // mapping of the module type to prop name to prop type here, and ultimately + // fix the documentation generator to also parse these properties correctly. + additionalPropTypes = map[string]map[string]string{ + // sdk and module_exports props are created at runtime using reflection. + // bpdocs isn't wired up to read runtime generated structs. + "sdk": { + "java_header_libs": "string_list", + "java_sdk_libs": "string_list", + "java_system_modules": "string_list", + "native_header_libs": "string_list", + "native_libs": "string_list", + "native_objects": "string_list", + "native_shared_libs": "string_list", + "native_static_libs": "string_list", + }, + "module_exports": { + "java_libs": "string_list", + "java_tests": "string_list", + "native_binaries": "string_list", + "native_shared_libs": "string_list", + }, + } + + // Certain module property names are blocklisted/ignored here, for the reasons commented. + ignoredPropNames = map[string]bool{ + "name": true, // redundant, since this is explicitly generated for every target + "from": true, // reserved keyword + "in": true, // reserved keyword + "arch": true, // interface prop type is not supported yet. + "multilib": true, // interface prop type is not supported yet. + "target": true, // interface prop type is not supported yet. + "visibility": true, // Bazel has native visibility semantics. Handle later. + "features": true, // There is already a built-in attribute 'features' which cannot be overridden. + } ) func targetNameWithVariant(c *blueprint.Context, logicModule blueprint.Module) string { @@ -206,9 +267,7 @@ func prettyPrint(propertyValue reflect.Value, indent int) (string, error) { structProps := extractStructProperties(propertyValue, indent) for _, k := range android.SortedStringKeys(structProps) { ret += makeIndent(indent + 1) - ret += "\"" + k + "\": " - ret += structProps[k] - ret += ",\n" + ret += fmt.Sprintf("%q: %s,\n", k, structProps[k]) } ret += makeIndent(indent) ret += "}" @@ -223,6 +282,10 @@ func prettyPrint(propertyValue reflect.Value, indent int) (string, error) { return ret, nil } +// Converts a reflected property struct value into a map of property names and property values, +// which each property value correctly pretty-printed and indented at the right nest level, +// since property structs can be nested. In Starlark, nested structs are represented as nested +// dicts: https://docs.bazel.build/skylark/lib/dict.html func extractStructProperties(structValue reflect.Value, indent int) map[string]string { if structValue.Kind() != reflect.Struct { panic(fmt.Errorf("Expected a reflect.Struct type, but got %s", structValue.Kind())) @@ -296,6 +359,102 @@ func extractModuleProperties(aModule android.Module) map[string]string { return ret } +// FIXME(b/168089390): In Bazel, rules ending with "_test" needs to be marked as +// testonly = True, forcing other rules that depend on _test rules to also be +// marked as testonly = True. This semantic constraint is not present in Soong. +// To work around, rename "*_test" rules to "*_test_". +func canonicalizeModuleType(moduleName string) string { + if strings.HasSuffix(moduleName, "_test") { + return moduleName + "_" + } + + return moduleName +} + +type RuleShim struct { + // The rule class shims contained in a bzl file. e.g. ["cc_object", "cc_library", ..] + rules []string + + // The generated string content of the bzl file. + content string +} + +// Create <module>.bzl containing Bazel rule shims for every module type available in Soong and +// user-specified Go plugins. +// +// This function reuses documentation generation APIs to ensure parity between modules-as-docs +// and modules-as-code, including the names and types of module properties. +func createRuleShims(packages []*bpdoc.Package) (map[string]RuleShim, error) { + var propToAttr func(prop bpdoc.Property, propName string) string + propToAttr = func(prop bpdoc.Property, propName string) string { + // dots are not allowed in Starlark attribute names. Substitute them with double underscores. + propName = strings.ReplaceAll(propName, ".", "__") + if !shouldGenerateAttribute(propName) { + return "" + } + + // Canonicalize and normalize module property types to Bazel attribute types + starlarkAttrType := prop.Type + if starlarkAttrType == "list of strings" { + starlarkAttrType = "string_list" + } else if starlarkAttrType == "int64" { + starlarkAttrType = "int" + } else if starlarkAttrType == "" { + var attr string + for _, nestedProp := range prop.Properties { + nestedAttr := propToAttr(nestedProp, propName+"__"+nestedProp.Name) + if nestedAttr != "" { + // TODO(b/167662930): Fix nested props resulting in too many attributes. + // Let's still generate these, but comment them out. + attr += "# " + nestedAttr + } + } + return attr + } + + if !allowedPropTypes[starlarkAttrType] { + return "" + } + + return fmt.Sprintf(" %q: attr.%s(),\n", propName, starlarkAttrType) + } + + ruleShims := map[string]RuleShim{} + for _, pkg := range packages { + content := "load(\":providers.bzl\", \"SoongModuleInfo\")\n" + + bzlFileName := strings.ReplaceAll(pkg.Path, "android/soong/", "") + bzlFileName = strings.ReplaceAll(bzlFileName, ".", "_") + bzlFileName = strings.ReplaceAll(bzlFileName, "/", "_") + + rules := []string{} + + for _, moduleTypeTemplate := range moduleTypeDocsToTemplates(pkg.ModuleTypes) { + attrs := `{ + "module_name": attr.string(mandatory = True), + "module_variant": attr.string(), + "module_deps": attr.label_list(providers = [SoongModuleInfo]), +` + for _, prop := range moduleTypeTemplate.Properties { + attrs += propToAttr(prop, prop.Name) + } + + for propName, propType := range additionalPropTypes[moduleTypeTemplate.Name] { + attrs += fmt.Sprintf(" %q: attr.%s(),\n", propName, propType) + } + + attrs += " }," + + rule := canonicalizeModuleType(moduleTypeTemplate.Name) + content += fmt.Sprintf(moduleRuleShim, rule, attrs) + rules = append(rules, rule) + } + + ruleShims[bzlFileName] = RuleShim{content: content, rules: rules} + } + return ruleShims, nil +} + func createBazelOverlay(ctx *android.Context, bazelOverlayDir string) error { blueprintCtx := ctx.Context blueprintCtx.VisitAllModules(func(module blueprint.Module) { @@ -316,21 +475,50 @@ func createBazelOverlay(ctx *android.Context, bazelOverlayDir string) error { return err } - return writeReadOnlyFile(bazelOverlayDir, "soong_module.bzl", soongModuleBzl) + if err := writeReadOnlyFile(bazelOverlayDir, "providers.bzl", providersBzl); err != nil { + return err + } + + packages, err := getPackages(ctx) + if err != nil { + return err + } + ruleShims, err := createRuleShims(packages) + if err != nil { + return err + } + + for bzlFileName, ruleShim := range ruleShims { + if err := writeReadOnlyFile(bazelOverlayDir, bzlFileName+".bzl", ruleShim.content); err != nil { + return err + } + } + + return writeReadOnlyFile(bazelOverlayDir, "soong_module.bzl", generateSoongModuleBzl(ruleShims)) } -var ignoredProps map[string]bool = map[string]bool{ - "name": true, // redundant, since this is explicitly generated for every target - "from": true, // reserved keyword - "in": true, // reserved keyword - "arch": true, // interface prop type is not supported yet. - "multilib": true, // interface prop type is not supported yet. - "target": true, // interface prop type is not supported yet. - "visibility": true, // Bazel has native visibility semantics. Handle later. +// Generate the content of soong_module.bzl with the rule shim load statements +// and mapping of module_type to rule shim map for every module type in Soong. +func generateSoongModuleBzl(bzlLoads map[string]RuleShim) string { + var loadStmts string + var moduleRuleMap string + for bzlFileName, ruleShim := range bzlLoads { + loadStmt := "load(\"//:" + loadStmt += bzlFileName + loadStmt += ".bzl\"" + for _, rule := range ruleShim.rules { + loadStmt += fmt.Sprintf(", %q", rule) + moduleRuleMap += " \"" + rule + "\": " + rule + ",\n" + } + loadStmt += ")\n" + loadStmts += loadStmt + } + + return fmt.Sprintf(soongModuleBzl, loadStmts, moduleRuleMap) } func shouldGenerateAttribute(prop string) bool { - return !ignoredProps[prop] + return !ignoredPropNames[prop] } // props is an unsorted map. This function ensures that @@ -367,9 +555,7 @@ func generateSoongModuleTarget( depLabelList := "[\n" for depLabel, _ := range depLabels { - depLabelList += " \"" - depLabelList += depLabel - depLabelList += "\",\n" + depLabelList += fmt.Sprintf(" %q,\n", depLabel) } depLabelList += " ]" @@ -377,7 +563,7 @@ func generateSoongModuleTarget( soongModuleTarget, targetNameWithVariant(blueprintCtx, module), blueprintCtx.ModuleName(module), - blueprintCtx.ModuleType(module), + canonicalizeModuleType(blueprintCtx.ModuleType(module)), blueprintCtx.ModuleSubDir(module), depLabelList, attributes) @@ -410,11 +596,12 @@ func buildFileForModule(ctx *blueprint.Context, module blueprint.Module) (*os.Fi return f, nil } -// The overlay directory should be read-only, sufficient for bazel query. +// The overlay directory should be read-only, sufficient for bazel query. The files +// are not intended to be edited by end users. func writeReadOnlyFile(dir string, baseName string, content string) error { - workspaceFile := filepath.Join(bazelOverlayDir, baseName) + pathToFile := filepath.Join(bazelOverlayDir, baseName) // 0444 is read-only - return ioutil.WriteFile(workspaceFile, []byte(content), 0444) + return ioutil.WriteFile(pathToFile, []byte(content), 0444) } func isZero(value reflect.Value) bool { diff --git a/cmd/soong_build/bazel_overlay_test.go b/cmd/soong_build/bazel_overlay_test.go index 8db784d6b..f0c851521 100644 --- a/cmd/soong_build/bazel_overlay_test.go +++ b/cmd/soong_build/bazel_overlay_test.go @@ -18,7 +18,10 @@ import ( "android/soong/android" "io/ioutil" "os" + "strings" "testing" + + "github.com/google/blueprint/bootstrap/bpdoc" ) var buildDir string @@ -253,3 +256,209 @@ func TestGenerateBazelOverlayFromBlueprint(t *testing.T) { } } } + +func createPackageFixtures() []*bpdoc.Package { + properties := []bpdoc.Property{ + bpdoc.Property{ + Name: "int64_prop", + Type: "int64", + }, + bpdoc.Property{ + Name: "int_prop", + Type: "int", + }, + bpdoc.Property{ + Name: "bool_prop", + Type: "bool", + }, + bpdoc.Property{ + Name: "string_prop", + Type: "string", + }, + bpdoc.Property{ + Name: "string_list_prop", + Type: "list of strings", + }, + bpdoc.Property{ + Name: "nested_prop", + Type: "", + Properties: []bpdoc.Property{ + bpdoc.Property{ + Name: "int_prop", + Type: "int", + }, + bpdoc.Property{ + Name: "bool_prop", + Type: "bool", + }, + bpdoc.Property{ + Name: "string_prop", + Type: "string", + }, + }, + }, + bpdoc.Property{ + Name: "unknown_type", + Type: "unknown", + }, + } + + fooPropertyStruct := &bpdoc.PropertyStruct{ + Name: "FooProperties", + Properties: properties, + } + + moduleTypes := []*bpdoc.ModuleType{ + &bpdoc.ModuleType{ + Name: "foo_library", + PropertyStructs: []*bpdoc.PropertyStruct{ + fooPropertyStruct, + }, + }, + + &bpdoc.ModuleType{ + Name: "foo_binary", + PropertyStructs: []*bpdoc.PropertyStruct{ + fooPropertyStruct, + }, + }, + &bpdoc.ModuleType{ + Name: "foo_test", + PropertyStructs: []*bpdoc.PropertyStruct{ + fooPropertyStruct, + }, + }, + } + + return [](*bpdoc.Package){ + &bpdoc.Package{ + Name: "foo_language", + Path: "android/soong/foo", + ModuleTypes: moduleTypes, + }, + } +} + +func TestGenerateModuleRuleShims(t *testing.T) { + ruleShims, err := createRuleShims(createPackageFixtures()) + if err != nil { + panic(err) + } + + if len(ruleShims) != 1 { + t.Errorf("Expected to generate 1 rule shim, but got %d", len(ruleShims)) + } + + fooRuleShim := ruleShims["foo"] + expectedRules := []string{"foo_binary", "foo_library", "foo_test_"} + + if len(fooRuleShim.rules) != 3 { + t.Errorf("Expected 3 rules, but got %d", len(fooRuleShim.rules)) + } + + for i, rule := range fooRuleShim.rules { + if rule != expectedRules[i] { + t.Errorf("Expected rule shim to contain %s, but got %s", expectedRules[i], rule) + } + } + + expectedBzl := `load(":providers.bzl", "SoongModuleInfo") + +def _foo_binary_impl(ctx): + return [SoongModuleInfo()] + +foo_binary = rule( + implementation = _foo_binary_impl, + attrs = { + "module_name": attr.string(mandatory = True), + "module_variant": attr.string(), + "module_deps": attr.label_list(providers = [SoongModuleInfo]), + "bool_prop": attr.bool(), + "int64_prop": attr.int(), + "int_prop": attr.int(), +# "nested_prop__int_prop": attr.int(), +# "nested_prop__bool_prop": attr.bool(), +# "nested_prop__string_prop": attr.string(), + "string_list_prop": attr.string_list(), + "string_prop": attr.string(), + }, +) + +def _foo_library_impl(ctx): + return [SoongModuleInfo()] + +foo_library = rule( + implementation = _foo_library_impl, + attrs = { + "module_name": attr.string(mandatory = True), + "module_variant": attr.string(), + "module_deps": attr.label_list(providers = [SoongModuleInfo]), + "bool_prop": attr.bool(), + "int64_prop": attr.int(), + "int_prop": attr.int(), +# "nested_prop__int_prop": attr.int(), +# "nested_prop__bool_prop": attr.bool(), +# "nested_prop__string_prop": attr.string(), + "string_list_prop": attr.string_list(), + "string_prop": attr.string(), + }, +) + +def _foo_test__impl(ctx): + return [SoongModuleInfo()] + +foo_test_ = rule( + implementation = _foo_test__impl, + attrs = { + "module_name": attr.string(mandatory = True), + "module_variant": attr.string(), + "module_deps": attr.label_list(providers = [SoongModuleInfo]), + "bool_prop": attr.bool(), + "int64_prop": attr.int(), + "int_prop": attr.int(), +# "nested_prop__int_prop": attr.int(), +# "nested_prop__bool_prop": attr.bool(), +# "nested_prop__string_prop": attr.string(), + "string_list_prop": attr.string_list(), + "string_prop": attr.string(), + }, +) +` + + if fooRuleShim.content != expectedBzl { + t.Errorf( + "Expected the generated rule shim bzl to be:\n%s\nbut got:\n%s", + expectedBzl, + fooRuleShim.content) + } +} + +func TestGenerateSoongModuleBzl(t *testing.T) { + ruleShims, err := createRuleShims(createPackageFixtures()) + if err != nil { + panic(err) + } + actualSoongModuleBzl := generateSoongModuleBzl(ruleShims) + + expectedLoad := "load(\"//:foo.bzl\", \"foo_binary\", \"foo_library\", \"foo_test_\")" + expectedRuleMap := `soong_module_rule_map = { + "foo_binary": foo_binary, + "foo_library": foo_library, + "foo_test_": foo_test_, +}` + if !strings.Contains(actualSoongModuleBzl, expectedLoad) { + t.Errorf( + "Generated soong_module.bzl:\n\n%s\n\n"+ + "Could not find the load statement in the generated soong_module.bzl:\n%s", + actualSoongModuleBzl, + expectedLoad) + } + + if !strings.Contains(actualSoongModuleBzl, expectedRuleMap) { + t.Errorf( + "Generated soong_module.bzl:\n\n%s\n\n"+ + "Could not find the module -> rule map in the generated soong_module.bzl:\n%s", + actualSoongModuleBzl, + expectedRuleMap) + } +} diff --git a/cmd/soong_build/writedocs.go b/cmd/soong_build/writedocs.go index c1368469c..5fb6e6ba2 100644 --- a/cmd/soong_build/writedocs.go +++ b/cmd/soong_build/writedocs.go @@ -95,14 +95,17 @@ func moduleTypeDocsToTemplates(moduleTypeList []*bpdoc.ModuleType) []moduleTypeT return result } -func writeDocs(ctx *android.Context, filename string) error { +func getPackages(ctx *android.Context) ([]*bpdoc.Package, error) { moduleTypeFactories := android.ModuleTypeFactories() bpModuleTypeFactories := make(map[string]reflect.Value) for moduleType, factory := range moduleTypeFactories { bpModuleTypeFactories[moduleType] = reflect.ValueOf(factory) } + return bootstrap.ModuleTypeDocs(ctx.Context, bpModuleTypeFactories) +} - packages, err := bootstrap.ModuleTypeDocs(ctx.Context, bpModuleTypeFactories) +func writeDocs(ctx *android.Context, filename string) error { + packages, err := getPackages(ctx) if err != nil { return err } diff --git a/dexpreopt/config.go b/dexpreopt/config.go index 3ef8b8dd8..21f7bb3ee 100644 --- a/dexpreopt/config.go +++ b/dexpreopt/config.go @@ -100,6 +100,21 @@ type GlobalSoongConfig struct { ConstructContext android.Path } +// These libs are added as optional dependencies (<uses-library> with android:required set to false). +// This is because they haven't existed prior to certain SDK version, but classes in them were in +// bootclasspath jars, etc. So making them hard dependencies (android:required=true) would prevent +// apps from being installed to such legacy devices. +var OptionalCompatUsesLibs = []string{ + "org.apache.http.legacy", + "android.test.base", + "android.test.mock", +} + +var CompatUsesLibs = []string{ + "android.hidl.base-V1.0-java", + "android.hidl.manager-V1.0-java", +} + const UnknownInstallLibraryPath = "error" // LibraryPath contains paths to the library DEX jar on host and on device. @@ -112,7 +127,29 @@ type LibraryPath struct { type LibraryPaths map[string]*LibraryPath // Add a new library path to the map, unless a path for this library already exists. -func (libPaths LibraryPaths) addLibraryPath(ctx android.PathContext, lib string, hostPath, installPath android.Path) { +// If necessary, check that the build and install paths exist. +func (libPaths LibraryPaths) addLibraryPath(ctx android.ModuleContext, lib string, + hostPath, installPath android.Path, strict bool) { + + // If missing dependencies are allowed, the build shouldn't fail when a <uses-library> is + // not found. However, this is likely to result is disabling dexpreopt, as it won't be + // possible to construct class loader context without on-host and on-device library paths. + strict = strict && !ctx.Config().AllowMissingDependencies() + + if hostPath == nil && strict { + android.ReportPathErrorf(ctx, "unknown build path to <uses-library> '%s'", lib) + } + + if installPath == nil { + if android.InList(lib, CompatUsesLibs) || android.InList(lib, OptionalCompatUsesLibs) { + // Assume that compatibility libraries are installed in /system/framework. + installPath = android.PathForModuleInstall(ctx, "framework", lib+".jar") + } else if strict { + android.ReportPathErrorf(ctx, "unknown install path to <uses-library> '%s'", lib) + } + } + + // Add a library only if the build and install path to it is known. if _, present := libPaths[lib]; !present { var devicePath string if installPath != nil { @@ -128,31 +165,17 @@ func (libPaths LibraryPaths) addLibraryPath(ctx android.PathContext, lib string, } } -// Add a new library path to the map. Ensure that the build path to the library exists. -func (libPaths LibraryPaths) AddLibraryPath(ctx android.PathContext, lib string, hostPath, installPath android.Path) { - if hostPath != nil && installPath != nil { - // Add a library only if the build and install path to it is known. - libPaths.addLibraryPath(ctx, lib, hostPath, installPath) - } else if ctx.Config().AllowMissingDependencies() { - // If missing dependencies are allowed, the build shouldn't fail when a <uses-library> is - // not found. However, this is likely to result is disabling dexpreopt, as it won't be - // possible to construct class loader context without on-host and on-device library paths. - } else { - // Error on libraries with unknown paths. - if hostPath == nil { - android.ReportPathErrorf(ctx, "unknown build path to <uses-library> '%s'", lib) - } else { - android.ReportPathErrorf(ctx, "unknown install path to <uses-library> '%s'", lib) - } - } +// Add a new library path to the map. Enforce checks that the library paths exist. +func (libPaths LibraryPaths) AddLibraryPath(ctx android.ModuleContext, lib string, hostPath, installPath android.Path) { + libPaths.addLibraryPath(ctx, lib, hostPath, installPath, true) } // Add a new library path to the map, if the library exists (name is not nil). -func (libPaths LibraryPaths) MaybeAddLibraryPath(ctx android.PathContext, lib *string, hostPath, installPath android.Path) { +// Don't enforce checks that the library paths exist. Some libraries may be missing from the build, +// but their names still need to be added to <uses-library> tags in the manifest. +func (libPaths LibraryPaths) MaybeAddLibraryPath(ctx android.ModuleContext, lib *string, hostPath, installPath android.Path) { if lib != nil { - // Don't check the build paths, add in any case. Some libraries may be missing from the - // build, but their names still need to be added to <uses-library> tags in the manifest. - libPaths.addLibraryPath(ctx, *lib, hostPath, installPath) + libPaths.addLibraryPath(ctx, *lib, hostPath, installPath, false) } } diff --git a/java/Android.bp b/java/Android.bp index e345014ce..92e8ca458 100644 --- a/java/Android.bp +++ b/java/Android.bp @@ -59,6 +59,7 @@ bootstrap_go_package { "device_host_converter_test.go", "dexpreopt_test.go", "dexpreopt_bootjars_test.go", + "hiddenapi_singleton_test.go", "java_test.go", "jdeps_test.go", "kotlin_test.go", diff --git a/java/android_manifest.go b/java/android_manifest.go index 41fcafe0c..62cd11203 100644 --- a/java/android_manifest.go +++ b/java/android_manifest.go @@ -42,16 +42,6 @@ var manifestMergerRule = pctx.AndroidStaticRule("manifestMerger", }, "args", "libs") -// These two libs are added as optional dependencies (<uses-library> with -// android:required set to false). This is because they haven't existed in pre-P -// devices, but classes in them were in bootclasspath jars, etc. So making them -// hard dependencies (android:required=true) would prevent apps from being -// installed to such legacy devices. -var optionalUsesLibs = []string{ - "android.test.base", - "android.test.mock", -} - // Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext, sdkLibraries dexpreopt.LibraryPaths, isLibrary, useEmbeddedNativeLibs, usesNonSdkApis, useEmbeddedDex, hasNoCode bool, loggingParent string) android.Path { @@ -81,7 +71,7 @@ func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext } for _, usesLib := range android.SortedStringKeys(sdkLibraries) { - if inList(usesLib, optionalUsesLibs) { + if inList(usesLib, dexpreopt.OptionalCompatUsesLibs) { args = append(args, "--optional-uses-library", usesLib) } else { args = append(args, "--uses-library", usesLib) diff --git a/java/app.go b/java/app.go index dbc09e9df..ae7373fc7 100755 --- a/java/app.go +++ b/java/app.go @@ -787,7 +787,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { // Add implicit SDK libraries to <uses-library> list. for _, usesLib := range android.SortedStringKeys(a.aapt.sdkLibraries) { - a.usesLibrary.addLib(usesLib, inList(usesLib, optionalUsesLibs)) + a.usesLibrary.addLib(usesLib, inList(usesLib, dexpreopt.OptionalCompatUsesLibs)) } // Check that the <uses-library> list is coherent with the manifest. @@ -1947,11 +1947,8 @@ func (u *usesLibrary) deps(ctx android.BottomUpMutatorContext, hasFrameworkLibs if hasFrameworkLibs { // Dexpreopt needs paths to the dex jars of these libraries in order to construct // class loader context for dex2oat. Add them as a dependency with a special tag. - ctx.AddVariationDependencies(nil, usesLibCompatTag, - "org.apache.http.legacy", - "android.hidl.base-V1.0-java", - "android.hidl.manager-V1.0-java") - ctx.AddVariationDependencies(nil, usesLibCompatTag, optionalUsesLibs...) + ctx.AddVariationDependencies(nil, usesLibTag, dexpreopt.CompatUsesLibs...) + ctx.AddVariationDependencies(nil, usesLibTag, dexpreopt.OptionalCompatUsesLibs...) } } } @@ -1969,27 +1966,14 @@ func (u *usesLibrary) usesLibraryPaths(ctx android.ModuleContext) dexpreopt.Libr usesLibPaths := make(dexpreopt.LibraryPaths) if !ctx.Config().UnbundledBuild() { - ctx.VisitDirectDeps(func(m android.Module) { - tag := ctx.OtherModuleDependencyTag(m) - if tag == usesLibTag || tag == usesLibCompatTag { - dep := ctx.OtherModuleName(m) - - if lib, ok := m.(Dependency); ok { - buildPath := lib.DexJarBuildPath() - installPath := lib.DexJarInstallPath() - if installPath == nil && tag == usesLibCompatTag { - // assume that compatibility libraries are in /system/framework - installPath = android.PathForModuleInstall(ctx, "framework", dep+".jar") - } - usesLibPaths.AddLibraryPath(ctx, dep, buildPath, installPath) - - } else if ctx.Config().AllowMissingDependencies() { - ctx.AddMissingDependencies([]string{dep}) - - } else { - ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must be "+ - "a java library", dep) - } + ctx.VisitDirectDepsWithTag(usesLibTag, func(m android.Module) { + dep := ctx.OtherModuleName(m) + if lib, ok := m.(Dependency); ok { + usesLibPaths.AddLibraryPath(ctx, dep, lib.DexJarBuildPath(), lib.DexJarInstallPath()) + } else if ctx.Config().AllowMissingDependencies() { + ctx.AddMissingDependencies([]string{dep}) + } else { + ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must be a java library", dep) } }) } diff --git a/java/droiddoc.go b/java/droiddoc.go index 7073eff48..e39a556e7 100644 --- a/java/droiddoc.go +++ b/java/droiddoc.go @@ -181,12 +181,6 @@ type DroiddocProperties struct { // filegroup or genrule can be included within this property. Knowntags []string `android:"path"` - // the generated public API filename by Doclava. - Api_filename *string - - // the generated removed API filename by Doclava. - Removed_api_filename *string - // if set to true, generate docs through Dokka instead of Doclava. Dokka_enabled *bool @@ -195,10 +189,10 @@ type DroiddocProperties struct { } type DroidstubsProperties struct { - // the generated public API filename by Metalava. + // The generated public API filename by Metalava, defaults to <module>_api.txt Api_filename *string - // the generated removed API filename by Metalava. + // the generated removed API filename by Metalava, defaults to <module>_removed.txt Removed_api_filename *string // the generated removed Dex API filename by Metalava. @@ -1127,7 +1121,8 @@ func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuil if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") || apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") || String(d.properties.Api_filename) != "" { - d.apiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_api.txt") + filename := proptools.StringDefault(d.properties.Api_filename, ctx.ModuleName()+"_api.txt") + d.apiFile = android.PathForModuleOut(ctx, filename) cmd.FlagWithOutput("--api ", d.apiFile) d.apiFilePath = d.apiFile } @@ -1135,7 +1130,8 @@ func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuil if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") || apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") || String(d.properties.Removed_api_filename) != "" { - d.removedApiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_removed.txt") + filename := proptools.StringDefault(d.properties.Removed_api_filename, ctx.ModuleName()+"_removed.txt") + d.removedApiFile = android.PathForModuleOut(ctx, filename) cmd.FlagWithOutput("--removed-api ", d.removedApiFile) } diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go index 29b6bcd7d..b6af3bf28 100644 --- a/java/hiddenapi_singleton.go +++ b/java/hiddenapi_singleton.go @@ -163,6 +163,7 @@ func stubFlagsRule(ctx android.SingletonContext) { return } } + bootDexJars = append(bootDexJars, jar) } } diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go new file mode 100644 index 000000000..bcca93a00 --- /dev/null +++ b/java/hiddenapi_singleton_test.go @@ -0,0 +1,136 @@ +// Copyright 2020 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package java + +import ( + "android/soong/android" + "strings" + "testing" +) + +func testConfigWithBootJars(bp string, bootJars []string) android.Config { + config := testConfig(nil, bp, nil) + config.TestProductVariables.BootJars = bootJars + return config +} + +func testContextWithHiddenAPI() *android.TestContext { + ctx := testContext() + ctx.RegisterSingletonType("hiddenapi", hiddenAPISingletonFactory) + return ctx +} + +func testHiddenAPI(t *testing.T, bp string, bootJars []string) (*android.TestContext, android.Config) { + t.Helper() + + config := testConfigWithBootJars(bp, bootJars) + ctx := testContextWithHiddenAPI() + + run(t, ctx, config) + + return ctx, config +} + +func TestHiddenAPISingleton(t *testing.T) { + ctx, _ := testHiddenAPI(t, ` + java_library { + name: "foo", + srcs: ["a.java"], + compile_dex: true, + } + `, []string{":foo"}) + + hiddenAPI := ctx.SingletonForTests("hiddenapi") + hiddenapiRule := hiddenAPI.Rule("hiddenapi") + want := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/aligned/foo.jar" + if !strings.Contains(hiddenapiRule.RuleParams.Command, want) { + t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", want, hiddenapiRule.RuleParams.Command) + } +} + +func TestHiddenAPISingletonWithPrebuilt(t *testing.T) { + ctx, _ := testHiddenAPI(t, ` + java_import { + name: "foo", + jars: ["a.jar"], + compile_dex: true, + } + `, []string{":foo"}) + + hiddenAPI := ctx.SingletonForTests("hiddenapi") + hiddenapiRule := hiddenAPI.Rule("hiddenapi") + want := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/dex/foo.jar" + if !strings.Contains(hiddenapiRule.RuleParams.Command, want) { + t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", want, hiddenapiRule.RuleParams.Command) + } +} + +func TestHiddenAPISingletonWithPrebuiltUseSource(t *testing.T) { + ctx, _ := testHiddenAPI(t, ` + java_library { + name: "foo", + srcs: ["a.java"], + compile_dex: true, + } + + java_import { + name: "foo", + jars: ["a.jar"], + compile_dex: true, + prefer: false, + } + `, []string{":foo"}) + + hiddenAPI := ctx.SingletonForTests("hiddenapi") + hiddenapiRule := hiddenAPI.Rule("hiddenapi") + fromSourceJarArg := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/aligned/foo.jar" + if !strings.Contains(hiddenapiRule.RuleParams.Command, fromSourceJarArg) { + t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", fromSourceJarArg, hiddenapiRule.RuleParams.Command) + } + + prebuiltJarArg := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/dex/foo.jar" + if strings.Contains(hiddenapiRule.RuleParams.Command, prebuiltJarArg) { + t.Errorf("Did not expect %s in hiddenapi command, but it was present: %s", prebuiltJarArg, hiddenapiRule.RuleParams.Command) + } +} + +func TestHiddenAPISingletonWithPrebuiltOverrideSource(t *testing.T) { + ctx, _ := testHiddenAPI(t, ` + java_library { + name: "foo", + srcs: ["a.java"], + compile_dex: true, + } + + java_import { + name: "foo", + jars: ["a.jar"], + compile_dex: true, + prefer: true, + } + `, []string{":foo"}) + + hiddenAPI := ctx.SingletonForTests("hiddenapi") + hiddenapiRule := hiddenAPI.Rule("hiddenapi") + prebuiltJarArg := "--boot-dex=" + buildDir + "/.intermediates/prebuilt_foo/android_common/dex/foo.jar" + if !strings.Contains(hiddenapiRule.RuleParams.Command, prebuiltJarArg) { + t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", prebuiltJarArg, hiddenapiRule.RuleParams.Command) + } + + fromSourceJarArg := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/aligned/foo.jar" + if strings.Contains(hiddenapiRule.RuleParams.Command, fromSourceJarArg) { + t.Errorf("Did not expect %s in hiddenapi command, but it was present: %s", fromSourceJarArg, hiddenapiRule.RuleParams.Command) + } +} diff --git a/java/java.go b/java/java.go index 9830c51f6..d67e9e098 100644 --- a/java/java.go +++ b/java/java.go @@ -570,7 +570,6 @@ var ( certificateTag = dependencyTag{name: "certificate"} instrumentationForTag = dependencyTag{name: "instrumentation_for"} usesLibTag = dependencyTag{name: "uses-library"} - usesLibCompatTag = dependencyTag{name: "uses-library-compat"} extraLintCheckTag = dependencyTag{name: "extra-lint-check"} ) @@ -1615,6 +1614,9 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { configurationName := j.ConfigurationName() primary := configurationName == ctx.ModuleName() + // If the prebuilt is being used rather than the from source, skip this + // module to prevent duplicated classes + primary = primary && !j.IsReplacedByPrebuilt() // Hidden API CSV generation and dex encoding dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, configurationName, primary, dexOutputFile, j.implementationJarFile, @@ -2685,6 +2687,13 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { return } + configurationName := j.BaseModuleName() + primary := j.Prebuilt().UsePrebuilt() + + // Hidden API CSV generation and dex encoding + dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, configurationName, primary, dexOutputFile, outputFile, + proptools.Bool(j.dexProperties.Uncompress_dex)) + j.dexJarFile = dexOutputFile } } diff --git a/java/testing.go b/java/testing.go index 70c857f39..322dc9ec6 100644 --- a/java/testing.go +++ b/java/testing.go @@ -145,6 +145,7 @@ func GatherRequiredDepsForTest() string { srcs: ["a.java"], sdk_version: "none", system_modules: "stable-core-platform-api-stubs-system-modules", + compile_dex: true, } `, extra) } diff --git a/rust/compiler.go b/rust/compiler.go index ddf1fac3a..664578d82 100644 --- a/rust/compiler.go +++ b/rust/compiler.go @@ -216,8 +216,8 @@ func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps { if !Bool(compiler.Properties.No_stdlibs) { for _, stdlib := range config.Stdlibs { - // If we're building for the primary host target, use the compiler's stdlibs - if ctx.Host() && ctx.TargetPrimary() { + // If we're building for the primary arch of the build host, use the compiler's stdlibs + if ctx.Target().Os == android.BuildOs && ctx.TargetPrimary() { stdlib = stdlib + "_" + ctx.toolchain().RustTriple() } diff --git a/rust/config/Android.bp b/rust/config/Android.bp index bcfac7c06..e0cc4ce07 100644 --- a/rust/config/Android.bp +++ b/rust/config/Android.bp @@ -16,5 +16,6 @@ bootstrap_go_package { "x86_linux_host.go", "x86_device.go", "x86_64_device.go", + "arm64_linux_host.go", ], } diff --git a/rust/config/arm64_device.go b/rust/config/arm64_device.go index a0c496d4a..7d13c42aa 100644 --- a/rust/config/arm64_device.go +++ b/rust/config/arm64_device.go @@ -71,9 +71,16 @@ func (t *toolchainArm64) Supported() bool { } func Arm64ToolchainFactory(arch android.Arch) Toolchain { + archVariant := arch.ArchVariant + if archVariant == "" { + // arch variants defaults to armv8-a. This is mostly for + // the host target which borrows toolchain configs from here. + archVariant = "armv8-a" + } + toolchainRustFlags := []string{ "${config.Arm64ToolchainRustFlags}", - "${config.Arm64" + arch.ArchVariant + "VariantRustFlags}", + "${config.Arm64" + archVariant + "VariantRustFlags}", } toolchainRustFlags = append(toolchainRustFlags, deviceGlobalRustFlags...) diff --git a/rust/config/arm64_linux_host.go b/rust/config/arm64_linux_host.go new file mode 100644 index 000000000..baf9cf836 --- /dev/null +++ b/rust/config/arm64_linux_host.go @@ -0,0 +1,24 @@ +// Copyright 2019 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. + +package config + +import ( + "android/soong/android" +) + +func init() { + // Linux_cross-arm64 uses the same rust toolchain as the Android-arm64 + registerToolchainFactory(android.LinuxBionic, android.Arm64, Arm64ToolchainFactory) +} diff --git a/rust/rust.go b/rust/rust.go index 4cba6d6b1..b98992c9b 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -560,21 +560,6 @@ func (mod *Module) Init() android.Module { android.InitAndroidArchModule(mod, mod.hod, mod.multilib) android.InitDefaultableModule(mod) - - // Explicitly disable unsupported targets. - android.AddLoadHook(mod, func(ctx android.LoadHookContext) { - disableTargets := struct { - Target struct { - Linux_bionic struct { - Enabled *bool - } - } - }{} - disableTargets.Target.Linux_bionic.Enabled = proptools.BoolPtr(false) - - ctx.AppendProperties(&disableTargets) - }) - return mod } |