diff options
75 files changed, 1226 insertions, 723 deletions
diff --git a/android/Android.bp b/android/Android.bp index cbd345945..f58a47296 100644 --- a/android/Android.bp +++ b/android/Android.bp @@ -88,6 +88,7 @@ bootstrap_go_package { "test_asserts.go", "test_suites.go", "testing.go", + "updatable_modules.go", "util.go", "variable.go", "visibility.go", diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go index af82942cb..aa4363c0b 100644 --- a/android/allowlists/allowlists.go +++ b/android/allowlists/allowlists.go @@ -257,6 +257,7 @@ var ( "packages/apps/QuickSearchBox":/* recursive = */ true, "packages/apps/WallpaperPicker":/* recursive = */ false, + "prebuilts/bazel":/* recursive = */ true, "prebuilts/bundletool":/* recursive = */ true, "prebuilts/gcc":/* recursive = */ true, "prebuilts/build-tools":/* recursive = */ true, @@ -365,6 +366,7 @@ var ( } Bp2buildModuleTypeAlwaysConvertList = []string{ + "linker_config", "java_import", "java_import_host", } @@ -439,7 +441,6 @@ var ( "art-script", // depends on unconverted modules: dalvikvm, dex2oat "bin2c_fastdeployagent", // depends on unconverted modules: deployagent "com.android.runtime", // depends on unconverted modules: bionic-linker-config, linkerconfig - "conv_linker_config", // depends on unconverted modules: linker_config_proto "currysrc", // depends on unconverted modules: currysrc_org.eclipse, guavalib, jopt-simple-4.9 "dex2oat-script", // depends on unconverted modules: dex2oat "generated_android_icu4j_resources", // depends on unconverted modules: android_icu4j_srcgen_binary, soong_zip diff --git a/android/androidmk.go b/android/androidmk.go index 832c7dfe3..006e43def 100644 --- a/android/androidmk.go +++ b/android/androidmk.go @@ -604,10 +604,6 @@ func (a *AndroidMkEntries) fillInEntries(ctx fillInEntriesContext, mod blueprint } } - if len(base.noticeFiles) > 0 { - a.SetString("LOCAL_NOTICE_FILE", strings.Join(base.noticeFiles.Strings(), " ")) - } - if host { makeOs := base.Os().String() if base.Os() == Linux || base.Os() == LinuxBionic || base.Os() == LinuxMusl { diff --git a/android/arch.go b/android/arch.go index e72614cfa..6acc8ad22 100644 --- a/android/arch.go +++ b/android/arch.go @@ -655,7 +655,8 @@ func archMutator(bpctx blueprint.BottomUpMutatorContext) { prefer32 := os == Windows // Determine the multilib selection for this module. - multilib, extraMultilib := decodeMultilib(base, os) + ignorePrefer32OnDevice := mctx.Config().IgnorePrefer32OnDevice() + multilib, extraMultilib := decodeMultilib(base, os, ignorePrefer32OnDevice) // Convert the multilib selection into a list of Targets. targets, err := decodeMultilibTargets(multilib, osTargets, prefer32) @@ -730,7 +731,7 @@ func addTargetProperties(m Module, target Target, multiTargets []Target, primary // multilib from the factory's call to InitAndroidArchModule if none was set. For modules that // called InitAndroidMultiTargetsArchModule it always returns "common" for multilib, and returns // the actual multilib in extraMultilib. -func decodeMultilib(base *ModuleBase, os OsType) (multilib, extraMultilib string) { +func decodeMultilib(base *ModuleBase, os OsType, ignorePrefer32OnDevice bool) (multilib, extraMultilib string) { // First check the "android.compile_multilib" or "host.compile_multilib" properties. switch os.Class { case Device: @@ -749,6 +750,13 @@ func decodeMultilib(base *ModuleBase, os OsType) (multilib, extraMultilib string multilib = base.commonProperties.Default_multilib } + // If a device is configured with multiple targets, this option + // force all device targets that prefer32 to be compiled only as + // the first target. + if ignorePrefer32OnDevice && os.Class == Device && (multilib == "prefer32" || multilib == "first_prefer32") { + multilib = "first" + } + if base.commonProperties.UseTargetVariants { // Darwin has the concept of "universal binaries" which is implemented in Soong by // building both x86_64 and arm64 variants, and having select module types know how to diff --git a/android/bazel_handler.go b/android/bazel_handler.go index 3be9805be..5804a46ed 100644 --- a/android/bazel_handler.go +++ b/android/bazel_handler.go @@ -91,6 +91,10 @@ type configKey struct { osType OsType } +func (c configKey) String() string { + return fmt.Sprintf("%s::%s", c.arch, c.osType) +} + // Map key to describe bazel cquery requests. type cqueryKey struct { label string @@ -98,6 +102,11 @@ type cqueryKey struct { configKey configKey } +func (c cqueryKey) String() string { + return fmt.Sprintf("cquery(%s,%s,%s)", c.label, c.requestType.Name(), c.configKey) + +} + // BazelContext is a context object useful for interacting with Bazel during // the course of a build. Use of Bazel to evaluate part of the build graph // is referred to as a "mixed build". (Some modules are managed by Soong, @@ -123,6 +132,9 @@ type BazelContext interface { // TODO(b/232976601): Remove. GetPythonBinary(label string, cfgKey configKey) (string, error) + // Returns the results of the GetApexInfo query (including output files) + GetApexInfo(label string, cfgkey configKey) (cquery.ApexCqueryInfo, error) + // ** end Cquery Results Retrieval Functions // Issues commands to Bazel to receive results for all cquery requests @@ -186,6 +198,7 @@ type MockBazelContext struct { LabelToOutputFiles map[string][]string LabelToCcInfo map[string]cquery.CcInfo LabelToPythonBinary map[string]string + LabelToApexInfo map[string]cquery.ApexCqueryInfo } func (m MockBazelContext) QueueBazelRequest(_ string, _ cqueryRequest, _ configKey) { @@ -207,6 +220,10 @@ func (m MockBazelContext) GetPythonBinary(label string, _ configKey) (string, er return result, nil } +func (n MockBazelContext) GetApexInfo(_ string, _ configKey) (cquery.ApexCqueryInfo, error) { + panic("unimplemented") +} + func (m MockBazelContext) InvokeBazel(_ Config) error { panic("unimplemented") } @@ -261,6 +278,14 @@ func (bazelCtx *bazelContext) GetPythonBinary(label string, cfgKey configKey) (s return "", fmt.Errorf("no bazel response found for %v", key) } +func (bazelCtx *bazelContext) GetApexInfo(label string, cfgKey configKey) (cquery.ApexCqueryInfo, error) { + key := cqueryKey{label, cquery.GetApexInfo, cfgKey} + if rawString, ok := bazelCtx.results[key]; ok { + return cquery.GetApexInfo.ParseResult(strings.TrimSpace(rawString)), nil + } + return cquery.ApexCqueryInfo{}, fmt.Errorf("no bazel response found for %v", key) +} + func (n noopBazelContext) QueueBazelRequest(_ string, _ cqueryRequest, _ configKey) { panic("unimplemented") } @@ -277,6 +302,10 @@ func (n noopBazelContext) GetPythonBinary(_ string, _ configKey) (string, error) panic("unimplemented") } +func (n noopBazelContext) GetApexInfo(_ string, _ configKey) (cquery.ApexCqueryInfo, error) { + panic("unimplemented") +} + func (n noopBazelContext) InvokeBazel(_ Config) error { panic("unimplemented") } @@ -399,19 +428,11 @@ type builtinBazelRunner struct{} func (r *builtinBazelRunner) issueBazelCommand(paths *bazelPaths, runName bazel.RunName, command bazelCommand, extraFlags ...string) (string, string, error) { cmdFlags := []string{ - // --noautodetect_server_javabase has the practical consequence of preventing Bazel from - // attempting to download rules_java, which is incompatible with - // --experimental_repository_disable_download set further below. - // rules_java is also not needed until mixed builds start building java targets. - // TODO(b/197958133): Once rules_java is pulled into AOSP, remove this flag. - "--noautodetect_server_javabase", "--output_base=" + absolutePath(paths.outputBase), command.command, - } - cmdFlags = append(cmdFlags, command.expression) - cmdFlags = append(cmdFlags, + command.expression, // TODO(asmundak): is it needed in every build? - "--profile="+shared.BazelMetricsFilename(paths, runName), + "--profile=" + shared.BazelMetricsFilename(paths, runName), // Set default platforms to canonicalized values for mixed builds requests. // If these are set in the bazelrc, they will have values that are @@ -432,21 +453,23 @@ func (r *builtinBazelRunner) issueBazelCommand(paths *bazelPaths, runName bazel. // Suppress noise "--ui_event_filters=-INFO", - "--noshow_progress") + "--noshow_progress"} cmdFlags = append(cmdFlags, extraFlags...) bazelCmd := exec.Command(paths.bazelPath, cmdFlags...) bazelCmd.Dir = absolutePath(paths.syntheticWorkspaceDir()) - bazelCmd.Env = append(os.Environ(), - "HOME="+paths.homeDir, + extraEnv := []string{ + "HOME=" + paths.homeDir, pwdPrefix(), - "BUILD_DIR="+absolutePath(paths.soongOutDir), + "BUILD_DIR=" + absolutePath(paths.soongOutDir), // Make OUT_DIR absolute here so tools/bazel.sh uses the correct // OUT_DIR at <root>/out, instead of <root>/out/soong/workspace/out. - "OUT_DIR="+absolutePath(paths.outDir()), + "OUT_DIR=" + absolutePath(paths.outDir()), // Disables local host detection of gcc; toolchain information is defined // explicitly in BUILD files. - "BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1") + "BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1", + } + bazelCmd.Env = append(os.Environ(), extraEnv...) stderr := &bytes.Buffer{} bazelCmd.Stderr = stderr @@ -657,6 +680,15 @@ def get_arch(target): fail("expected platform name of the form 'android_<arch>' or 'linux_<arch>', but was " + str(platforms)) return "UNKNOWN" +def json_for_file(key, file): + return '"' + key + '":"' + file.path + '"' + +def json_for_files(key, files): + return '"' + key + '":[' + ",".join(['"' + f.path + '"' for f in files]) + ']' + +def json_for_labels(key, ll): + return '"' + key + '":[' + ",".join(['"' + str(x) + '"' for x in ll]) + ']' + def format(target): id_string = str(target.label) + "|" + get_arch(target) @@ -734,7 +766,7 @@ func (context *bazelContext) InvokeBazel(config Config) error { cqueryOutput, cqueryErr, err := context.issueBazelCommand(context.paths, bazel.CqueryBuildRootRunName, cqueryCmd, "--output=starlark", "--starlark:file="+absolutePath(cqueryFileRelpath)) if err != nil { - err = ioutil.WriteFile(filepath.Join(soongInjectionPath, "cquery.out"), []byte(cqueryOutput), 0666) + _ = ioutil.WriteFile(filepath.Join(soongInjectionPath, "cquery.out"), []byte(cqueryOutput), 0666) } if err != nil { return err diff --git a/android/bazel_paths.go b/android/bazel_paths.go index 1d0a6d541..c030aa864 100644 --- a/android/bazel_paths.go +++ b/android/bazel_paths.go @@ -32,14 +32,14 @@ import ( // There is often a similar method for Bazel as there is for Soong path handling and should be used // in similar circumstances // -// Bazel Soong -// -// BazelLabelForModuleSrc PathForModuleSrc -// BazelLabelForModuleSrcExcludes PathForModuleSrcExcludes -// BazelLabelForModuleDeps n/a -// tbd PathForSource -// tbd ExistentPathsForSources -// PathForBazelOut PathForModuleOut +// Bazel Soong +// ============================================================== +// BazelLabelForModuleSrc PathForModuleSrc +// BazelLabelForModuleSrcExcludes PathForModuleSrcExcludes +// BazelLabelForModuleDeps n/a +// tbd PathForSource +// tbd ExistentPathsForSources +// PathForBazelOut PathForModuleOut // // Use cases: // * Module contains a property (often tagged `android:"path"`) that expects paths *relative to the @@ -68,7 +68,7 @@ import ( // cannot be resolved,the function will panic. This is often due to the dependency not being added // via an AddDependency* method. -// A minimal context interface to check if a module should be converted by bp2build, +// BazelConversionContext is a minimal context interface to check if a module should be converted by bp2build, // with functions containing information to match against allowlists and denylists. // If a module is deemed to be convertible by bp2build, then it should rely on a // BazelConversionPathContext for more functions for dep/path features. diff --git a/android/config.go b/android/config.go index 47346fcf1..8c7d789c8 100644 --- a/android/config.go +++ b/android/config.go @@ -1446,8 +1446,8 @@ func (c *config) ForceApexSymlinkOptimization() bool { return Bool(c.productVariables.ForceApexSymlinkOptimization) } -func (c *config) CompressedApex() bool { - return Bool(c.productVariables.CompressedApex) +func (c *config) ApexCompressionEnabled() bool { + return Bool(c.productVariables.CompressedApex) && !c.UnbundledBuildApps() } func (c *config) EnforceSystemCertificate() bool { @@ -1725,6 +1725,10 @@ func (c *deviceConfig) GenerateAidlNdkPlatformBackend() bool { return c.config.productVariables.GenerateAidlNdkPlatformBackend } +func (c *config) IgnorePrefer32OnDevice() bool { + return c.productVariables.IgnorePrefer32OnDevice +} + // The ConfiguredJarList struct provides methods for handling a list of (apex, jar) pairs. // Such lists are used in the build system for things like bootclasspath jars or system server jars. // The apex part is either an apex name, or a special names "platform" or "system_ext". Jar is a diff --git a/android/license_metadata.go b/android/license_metadata.go index f2ab0a44c..4ee5bf7ae 100644 --- a/android/license_metadata.go +++ b/android/license_metadata.go @@ -15,7 +15,6 @@ package android import ( - "fmt" "sort" "strings" @@ -67,6 +66,11 @@ func buildLicenseMetadata(ctx ModuleContext, licenseMetadataFile WritablePath) { return } + // Defaults add properties and dependencies that get processed on their own. + if ctx.OtherModuleDependencyTag(dep) == DefaultsDepTag { + return + } + if ctx.OtherModuleHasProvider(dep, LicenseMetadataProvider) { info := ctx.OtherModuleProvider(dep, LicenseMetadataProvider).(*LicenseMetadataInfo) allDepMetadataFiles = append(allDepMetadataFiles, info.LicenseMetadataPath) @@ -139,8 +143,6 @@ func buildLicenseMetadata(ctx ModuleContext, licenseMetadataFile WritablePath) { if len(outputFiles) > 0 { args = append(args, JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(outputFiles.Strings()), "-t ")) - } else { - args = append(args, fmt.Sprintf("-t //%s:%s", ctx.ModuleDir(), ctx.ModuleName())) } // Installed files diff --git a/android/metrics.go b/android/metrics.go index 1580f82b1..ecda0266d 100644 --- a/android/metrics.go +++ b/android/metrics.go @@ -32,8 +32,13 @@ type SoongMetrics struct { Variants int } -func ReadSoongMetrics(config Config) SoongMetrics { - return config.Get(soongMetricsOnceKey).(SoongMetrics) +func readSoongMetrics(config Config) (SoongMetrics, bool) { + soongMetrics, ok := config.Peek(soongMetricsOnceKey) + if ok { + return soongMetrics.(SoongMetrics), true + } else { + return SoongMetrics{}, false + } } func init() { @@ -60,9 +65,11 @@ func (soongMetricsSingleton) GenerateBuildActions(ctx SingletonContext) { func collectMetrics(config Config, eventHandler metrics.EventHandler) *soong_metrics_proto.SoongBuildMetrics { metrics := &soong_metrics_proto.SoongBuildMetrics{} - soongMetrics := ReadSoongMetrics(config) - metrics.Modules = proto.Uint32(uint32(soongMetrics.Modules)) - metrics.Variants = proto.Uint32(uint32(soongMetrics.Variants)) + soongMetrics, ok := readSoongMetrics(config) + if ok { + metrics.Modules = proto.Uint32(uint32(soongMetrics.Modules)) + metrics.Variants = proto.Uint32(uint32(soongMetrics.Variants)) + } memStats := runtime.MemStats{} runtime.ReadMemStats(&memStats) diff --git a/android/module.go b/android/module.go index 292508199..4dbfdd318 100644 --- a/android/module.go +++ b/android/module.go @@ -515,7 +515,6 @@ type Module interface { ExportedToMake() bool InitRc() Paths VintfFragments() Paths - NoticeFiles() Paths EffectiveLicenseFiles() Paths AddProperties(props ...interface{}) @@ -831,9 +830,6 @@ type commonProperties struct { // names of other modules to install on target if this module is installed Target_required []string `android:"arch_variant"` - // relative path to a file to include in the list of notices for the device - Notice *string `android:"path"` - // The OsType of artifacts that this module variant is responsible for creating. // // Set by osMutator @@ -1423,7 +1419,6 @@ type ModuleBase struct { checkbuildFiles Paths packagingSpecs []PackagingSpec packagingSpecsDepSet *packagingSpecsDepSet - noticeFiles Paths // katiInstalls tracks the install rules that were created by Soong but are being exported // to Make to convert to ninja rules so that Make can add additional dependencies. katiInstalls katiInstalls @@ -2054,10 +2049,6 @@ func (m *ModuleBase) Owner() string { return String(m.commonProperties.Owner) } -func (m *ModuleBase) NoticeFiles() Paths { - return m.noticeFiles -} - func (m *ModuleBase) setImageVariation(variant string) { m.commonProperties.ImageVariation = variant } @@ -2317,27 +2308,6 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) } }) - m.noticeFiles = make([]Path, 0) - optPath := OptionalPath{} - notice := proptools.StringDefault(m.commonProperties.Notice, "") - if module := SrcIsModule(notice); module != "" { - optPath = ctx.ExpandOptionalSource(¬ice, "notice") - } else if notice != "" { - noticePath := filepath.Join(ctx.ModuleDir(), notice) - optPath = ExistentPathForSource(ctx, noticePath) - } - if optPath.Valid() { - m.noticeFiles = append(m.noticeFiles, optPath.Path()) - } else { - for _, notice = range []string{"LICENSE", "LICENCE", "NOTICE"} { - noticePath := filepath.Join(ctx.ModuleDir(), notice) - optPath = ExistentPathForSource(ctx, noticePath) - if optPath.Valid() { - m.noticeFiles = append(m.noticeFiles, optPath.Path()) - } - } - } - licensesPropertyFlattener(ctx) if ctx.Failed() { return diff --git a/android/onceper.go b/android/onceper.go index 481cdea05..fa415d183 100644 --- a/android/onceper.go +++ b/android/onceper.go @@ -79,6 +79,17 @@ func (once *OncePer) Get(key OnceKey) interface{} { return once.maybeWaitFor(key, v) } +// Peek returns the value previously computed with Once for a given key. If Once has not +// been called for the given key Peek will return ok == false. +func (once *OncePer) Peek(key OnceKey) (interface{}, bool) { + v, ok := once.values.Load(key) + if !ok { + return nil, false + } + + return once.maybeWaitFor(key, v), true +} + // OnceStringSlice is the same as Once, but returns the value cast to a []string func (once *OncePer) OnceStringSlice(key OnceKey, value func() []string) []string { return once.Once(key, func() interface{} { return value() }).([]string) diff --git a/android/paths.go b/android/paths.go index d5cec9af7..f8e701822 100644 --- a/android/paths.go +++ b/android/paths.go @@ -1474,7 +1474,7 @@ func pathForModuleOut(ctx ModuleOutPathContext) OutputPath { // PathForVndkRefAbiDump returns an OptionalPath representing the path of the // reference abi dump for the given module. This is not guaranteed to be valid. func PathForVndkRefAbiDump(ctx ModuleInstallPathContext, version, fileName string, - isNdk, isLlndkOrVndk, isGzip bool) OptionalPath { + isNdk, isVndk, isGzip bool) OptionalPath { currentArchType := ctx.Arch().ArchType primaryArchType := ctx.Config().DevicePrimaryArchType() @@ -1486,7 +1486,7 @@ func PathForVndkRefAbiDump(ctx ModuleInstallPathContext, version, fileName strin var dirName string if isNdk { dirName = "ndk" - } else if isLlndkOrVndk { + } else if isVndk { dirName = "vndk" } else { dirName = "platform" // opt-in libs diff --git a/android/sdk.go b/android/sdk.go index 07b94b246..a71f7f211 100644 --- a/android/sdk.go +++ b/android/sdk.go @@ -985,6 +985,10 @@ type SdkMemberContext interface { // RequiresTrait returns true if this member is expected to provide the specified trait. RequiresTrait(trait SdkMemberTrait) bool + + // IsTargetBuildBeforeTiramisu return true if the target build release for which this snapshot is + // being generated is before Tiramisu, i.e. S. + IsTargetBuildBeforeTiramisu() bool } // ExportedComponentsInfo contains information about the components that this module exports to an diff --git a/apex/constants.go b/android/updatable_modules.go index c68edb724..71c76c56a 100644 --- a/apex/constants.go +++ b/android/updatable_modules.go @@ -12,11 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -package apex +package android -// This file contains branch specific constants. They are stored in a separate -// file to minimise the potential of merge conflicts between branches when -// the code from the package is changed. +// This file contains branch specific constants for building updatable modules. +// They are stored in a separate file to minimise the potential of merge +// conflicts between branches when the code from the package is changed. // The default manifest version for all the modules on this branch. // This version code will be used only if there is no version field in the @@ -33,4 +33,4 @@ package apex // * AOSP - xx9990000 // * x-mainline-prod - xx9990000 // * master - 990090000 -const defaultManifestVersion = "339990000" +const DefaultUpdatableModuleVersion = "339990000" diff --git a/android/variable.go b/android/variable.go index 50fc304d2..874b69d9c 100644 --- a/android/variable.go +++ b/android/variable.go @@ -447,6 +447,8 @@ type productVariables struct { SepolicyFreezeTestExtraPrebuiltDirs []string `json:",omitempty"` GenerateAidlNdkPlatformBackend bool `json:",omitempty"` + + IgnorePrefer32OnDevice bool `json:",omitempty"` } func boolPtr(v bool) *bool { diff --git a/apex/Android.bp b/apex/Android.bp index 6533c6103..018d0306d 100644 --- a/apex/Android.bp +++ b/apex/Android.bp @@ -26,7 +26,7 @@ bootstrap_go_package { "apex_sdk_member.go", "apex_singleton.go", "builder.go", - "constants.go", + "bp2build.go", "deapexer.go", "key.go", "prebuilt.go", diff --git a/apex/androidmk.go b/apex/androidmk.go index 938c8edd3..3373211a0 100644 --- a/apex/androidmk.go +++ b/apex/androidmk.go @@ -168,10 +168,6 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, mo if len(newDataPaths) > 0 { fmt.Fprintln(w, "LOCAL_TEST_DATA :=", strings.Join(android.AndroidMkDataPaths(newDataPaths), " ")) } - - if fi.module != nil && len(fi.module.NoticeFiles()) > 0 { - fmt.Fprintln(w, "LOCAL_NOTICE_FILE :=", strings.Join(fi.module.NoticeFiles().Strings(), " ")) - } } else { modulePath = pathWhenActivated fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", pathWhenActivated) diff --git a/apex/apex.go b/apex/apex.go index 7b6707ce6..09a578442 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -17,6 +17,7 @@ package apex import ( + "android/soong/bazel/cquery" "fmt" "path/filepath" "regexp" @@ -639,7 +640,7 @@ var ( fsTag = &dependencyTag{name: "filesystem", payload: true} bcpfTag = &dependencyTag{name: "bootclasspathFragment", payload: true, sourceOnly: true, memberType: java.BootclasspathFragmentSdkMemberType} sscpfTag = &dependencyTag{name: "systemserverclasspathFragment", payload: true, sourceOnly: true, memberType: java.SystemServerClasspathFragmentSdkMemberType} - compatConfigTag = &dependencyTag{name: "compatConfig", payload: true, sourceOnly: true} + compatConfigTag = &dependencyTag{name: "compatConfig", payload: true, sourceOnly: true, memberType: java.CompatConfigSdkMemberType} javaLibTag = &dependencyTag{name: "javaLib", payload: true} jniLibTag = &dependencyTag{name: "jniLib", payload: true} keyTag = &dependencyTag{name: "key"} @@ -1803,6 +1804,184 @@ func (f fsType) string() string { } } +var _ android.MixedBuildBuildable = (*apexBundle)(nil) + +func (a *apexBundle) IsMixedBuildSupported(ctx android.BaseModuleContext) bool { + return ctx.ModuleType() == "apex" && a.properties.ApexType == imageApex +} + +func (a *apexBundle) QueueBazelCall(ctx android.BaseModuleContext) { + bazelCtx := ctx.Config().BazelContext + bazelCtx.QueueBazelRequest(a.GetBazelLabel(ctx, a), cquery.GetApexInfo, android.GetConfigKey(ctx)) +} + +func (a *apexBundle) ProcessBazelQueryResponse(ctx android.ModuleContext) { + if !a.commonBuildActions(ctx) { + return + } + + a.setApexTypeAndSuffix(ctx) + a.setPayloadFsType(ctx) + a.setSystemLibLink(ctx) + + if a.properties.ApexType != zipApex { + a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx, a.primaryApexType) + } + + bazelCtx := ctx.Config().BazelContext + outputs, err := bazelCtx.GetApexInfo(a.GetBazelLabel(ctx, a), android.GetConfigKey(ctx)) + if err != nil { + ctx.ModuleErrorf(err.Error()) + return + } + a.installDir = android.PathForModuleInstall(ctx, "apex") + a.outputApexFile = android.PathForBazelOut(ctx, outputs.SignedOutput) + a.outputFile = a.outputApexFile + a.setCompression(ctx) + + a.publicKeyFile = android.PathForBazelOut(ctx, outputs.BundleKeyPair[0]) + a.privateKeyFile = android.PathForBazelOut(ctx, outputs.BundleKeyPair[1]) + a.containerCertificateFile = android.PathForBazelOut(ctx, outputs.ContainerKeyPair[0]) + a.containerPrivateKeyFile = android.PathForBazelOut(ctx, outputs.ContainerKeyPair[1]) + apexType := a.properties.ApexType + switch apexType { + case imageApex: + // TODO(asmundak): Bazel does not create these files yet. + // b/190817312 + a.htmlGzNotice = android.PathForBazelOut(ctx, "NOTICE.html.gz") + // b/239081457 + a.bundleModuleFile = android.PathForBazelOut(ctx, a.Name()+apexType.suffix()+"-base.zip") + // b/239081455 + a.nativeApisUsedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, a.Name()+"_using.txt")) + // b/239081456 + a.nativeApisBackedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, a.Name()+"_backing.txt")) + // b/239084755 + a.javaApisUsedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, a.Name()+"_using.xml")) + installSuffix := imageApexSuffix + if a.isCompressed { + installSuffix = imageCapexSuffix + } + a.installedFile = ctx.InstallFile(a.installDir, a.Name()+installSuffix, a.outputFile, + a.compatSymlinks.Paths()...) + default: + panic(fmt.Errorf("unexpected apex_type for the ProcessBazelQuery: %v", a.properties.ApexType)) + } + + /* + TODO(asmundak): compared to building an APEX with Soong, building it with Bazel does not + return filesInfo and requiredDeps fields (in the Soong build the latter is updated). + Fix this, as these fields are subsequently used in apex/androidmk.go and in apex/builder/go + To find out what Soong build puts there, run: + vctx := visitorContext{handleSpecialLibs: !android.Bool(a.properties.Ignore_system_library_special_case)} + ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool { + return a.depVisitor(&vctx, ctx, child, parent) + }) + vctx.normalizeFileInfo() + */ + +} + +func (a *apexBundle) setCompression(ctx android.ModuleContext) { + if a.properties.ApexType != imageApex { + a.isCompressed = false + } else if a.testOnlyShouldForceCompression() { + a.isCompressed = true + } else { + a.isCompressed = ctx.Config().ApexCompressionEnabled() && a.isCompressable() + } +} + +func (a *apexBundle) setSystemLibLink(ctx android.ModuleContext) { + // Optimization. If we are building bundled APEX, for the files that are gathered due to the + // transitive dependencies, don't place them inside the APEX, but place a symlink pointing + // the same library in the system partition, thus effectively sharing the same libraries + // across the APEX boundary. For unbundled APEX, all the gathered files are actually placed + // in the APEX. + a.linkToSystemLib = !ctx.Config().UnbundledBuild() && a.installable() + + // APEXes targeting other than system/system_ext partitions use vendor/product variants. + // So we can't link them to /system/lib libs which are core variants. + if a.SocSpecific() || a.DeviceSpecific() || (a.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) { + a.linkToSystemLib = false + } + + forced := ctx.Config().ForceApexSymlinkOptimization() + updatable := a.Updatable() || a.FutureUpdatable() + + // We don't need the optimization for updatable APEXes, as it might give false signal + // to the system health when the APEXes are still bundled (b/149805758). + if !forced && updatable && a.properties.ApexType == imageApex { + a.linkToSystemLib = false + } + + // We also don't want the optimization for host APEXes, because it doesn't make sense. + if ctx.Host() { + a.linkToSystemLib = false + } +} + +func (a *apexBundle) setPayloadFsType(ctx android.ModuleContext) { + switch proptools.StringDefault(a.properties.Payload_fs_type, ext4FsType) { + case ext4FsType: + a.payloadFsType = ext4 + case f2fsFsType: + a.payloadFsType = f2fs + case erofsFsType: + a.payloadFsType = erofs + default: + ctx.PropertyErrorf("payload_fs_type", "%q is not a valid filesystem for apex [ext4, f2fs, erofs]", *a.properties.Payload_fs_type) + } +} + +func (a *apexBundle) setApexTypeAndSuffix(ctx android.ModuleContext) { + // Set suffix and primaryApexType depending on the ApexType + buildFlattenedAsDefault := ctx.Config().FlattenApex() + switch a.properties.ApexType { + case imageApex: + if buildFlattenedAsDefault { + a.suffix = imageApexSuffix + } else { + a.suffix = "" + a.primaryApexType = true + + if ctx.Config().InstallExtraFlattenedApexes() { + a.requiredDeps = append(a.requiredDeps, a.Name()+flattenedSuffix) + } + } + case zipApex: + if proptools.String(a.properties.Payload_type) == "zip" { + a.suffix = "" + a.primaryApexType = true + } else { + a.suffix = zipApexSuffix + } + case flattenedApex: + if buildFlattenedAsDefault { + a.suffix = "" + a.primaryApexType = true + } else { + a.suffix = flattenedSuffix + } + } +} + +func (a apexBundle) isCompressable() bool { + return proptools.BoolDefault(a.overridableProperties.Compressible, false) && !a.testApex +} + +func (a *apexBundle) commonBuildActions(ctx android.ModuleContext) bool { + a.checkApexAvailability(ctx) + a.checkUpdatable(ctx) + a.CheckMinSdkVersion(ctx) + a.checkStaticLinkingToStubLibraries(ctx) + a.checkStaticExecutables(ctx) + if len(a.properties.Tests) > 0 && !a.testApex { + ctx.PropertyErrorf("tests", "property allowed only in apex_test module type") + return false + } + return true +} + type visitorContext struct { // all the files that will be included in this APEX filesInfo []apexFile @@ -2188,16 +2367,9 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { //////////////////////////////////////////////////////////////////////////////////////////// // 1) do some validity checks such as apex_available, min_sdk_version, etc. - a.checkApexAvailability(ctx) - a.checkUpdatable(ctx) - a.CheckMinSdkVersion(ctx) - a.checkStaticLinkingToStubLibraries(ctx) - a.checkStaticExecutables(ctx) - if len(a.properties.Tests) > 0 && !a.testApex { - ctx.PropertyErrorf("tests", "property allowed only in apex_test module type") + if !a.commonBuildActions(ctx) { return } - //////////////////////////////////////////////////////////////////////////////////////////// // 2) traverse the dependency tree to collect apexFile structs from them. @@ -2219,74 +2391,9 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.installDir = android.PathForModuleInstall(ctx, "apex") a.filesInfo = vctx.filesInfo - // Set suffix and primaryApexType depending on the ApexType - buildFlattenedAsDefault := ctx.Config().FlattenApex() - switch a.properties.ApexType { - case imageApex: - if buildFlattenedAsDefault { - a.suffix = imageApexSuffix - } else { - a.suffix = "" - a.primaryApexType = true - - if ctx.Config().InstallExtraFlattenedApexes() { - a.requiredDeps = append(a.requiredDeps, a.Name()+flattenedSuffix) - } - } - case zipApex: - if proptools.String(a.properties.Payload_type) == "zip" { - a.suffix = "" - a.primaryApexType = true - } else { - a.suffix = zipApexSuffix - } - case flattenedApex: - if buildFlattenedAsDefault { - a.suffix = "" - a.primaryApexType = true - } else { - a.suffix = flattenedSuffix - } - } - - switch proptools.StringDefault(a.properties.Payload_fs_type, ext4FsType) { - case ext4FsType: - a.payloadFsType = ext4 - case f2fsFsType: - a.payloadFsType = f2fs - case erofsFsType: - a.payloadFsType = erofs - default: - ctx.PropertyErrorf("payload_fs_type", "%q is not a valid filesystem for apex [ext4, f2fs, erofs]", *a.properties.Payload_fs_type) - } - - // Optimization. If we are building bundled APEX, for the files that are gathered due to the - // transitive dependencies, don't place them inside the APEX, but place a symlink pointing - // the same library in the system partition, thus effectively sharing the same libraries - // across the APEX boundary. For unbundled APEX, all the gathered files are actually placed - // in the APEX. - a.linkToSystemLib = !ctx.Config().UnbundledBuild() && a.installable() - - // APEXes targeting other than system/system_ext partitions use vendor/product variants. - // So we can't link them to /system/lib libs which are core variants. - if a.SocSpecific() || a.DeviceSpecific() || (a.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) { - a.linkToSystemLib = false - } - - forced := ctx.Config().ForceApexSymlinkOptimization() - updatable := a.Updatable() || a.FutureUpdatable() - - // We don't need the optimization for updatable APEXes, as it might give false signal - // to the system health when the APEXes are still bundled (b/149805758). - if !forced && updatable && a.properties.ApexType == imageApex { - a.linkToSystemLib = false - } - - // We also don't want the optimization for host APEXes, because it doesn't make sense. - if ctx.Host() { - a.linkToSystemLib = false - } - + a.setApexTypeAndSuffix(ctx) + a.setPayloadFsType(ctx) + a.setSystemLibLink(ctx) if a.properties.ApexType != zipApex { a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx, a.primaryApexType) } diff --git a/apex/apex_test.go b/apex/apex_test.go index dbe918010..52829417d 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -443,7 +443,6 @@ func TestBasicApex(t *testing.T) { srcs: ["mylib.cpp"], system_shared_libs: [], stl: "none", - notice: "custom_notice", static_libs: ["libstatic"], // TODO: remove //apex_available:platform apex_available: [ @@ -467,7 +466,6 @@ func TestBasicApex(t *testing.T) { srcs: ["mylib.cpp"], system_shared_libs: [], stl: "none", - notice: "custom_notice_for_static_lib", // TODO: remove //apex_available:platform apex_available: [ "//apex_available:platform", @@ -619,7 +617,7 @@ func TestDefaults(t *testing.T) { java_libs: ["myjar"], apps: ["AppFoo"], rros: ["rro"], - bpfs: ["bpf", "netd_test"], + bpfs: ["bpf", "netdTest"], updatable: false, } @@ -673,8 +671,8 @@ func TestDefaults(t *testing.T) { } bpf { - name: "netd_test", - srcs: ["netd_test.c"], + name: "netdTest", + srcs: ["netdTest.c"], sub_dir: "netd", } @@ -687,7 +685,7 @@ func TestDefaults(t *testing.T) { "overlay/blue/rro.apk", "etc/bpf/bpf.o", "etc/bpf/bpf2.o", - "etc/bpf/netd/netd_test.o", + "etc/bpf/netd/netdTest.o", }) } @@ -949,8 +947,10 @@ func TestApexWithStubs(t *testing.T) { // mylib2Cflags := ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"] // ensureNotContains(t, mylib2Cflags, "-include ") - // Ensure that genstub is invoked with --apex - ensureContains(t, "--apex", ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_3").Rule("genStubSrc").Args["flags"]) + // Ensure that genstub for platform-provided lib is invoked with --systemapi + ensureContains(t, ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_3").Rule("genStubSrc").Args["flags"], "--systemapi") + // Ensure that genstub for apex-provided lib is invoked with --apex + ensureContains(t, ctx.ModuleForTests("mylib3", "android_arm64_armv8-a_shared_12").Rule("genStubSrc").Args["flags"], "--apex") ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ "lib64/mylib.so", @@ -1134,8 +1134,8 @@ func TestApexWithStubsWithMinSdkVersion(t *testing.T) { mylib2Cflags := ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_29").Rule("cc").Args["cFlags"] ensureNotContains(t, mylib2Cflags, "-include ") - // Ensure that genstub is invoked with --apex - ensureContains(t, "--apex", ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_29").Rule("genStubSrc").Args["flags"]) + // Ensure that genstub is invoked with --systemapi + ensureContains(t, ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_29").Rule("genStubSrc").Args["flags"], "--systemapi") ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ "lib64/mylib.so", @@ -6151,7 +6151,7 @@ func TestOverrideApex(t *testing.T) { name: "override_myapex", base: "myapex", apps: ["override_app"], - bpfs: ["override_bpf"], + bpfs: ["overrideBpf"], prebuilts: ["override_myetc"], bootclasspath_fragments: ["override_bootclasspath_fragment"], systemserverclasspath_fragments: ["override_systemserverclasspath_fragment"], @@ -6201,8 +6201,8 @@ func TestOverrideApex(t *testing.T) { } bpf { - name: "override_bpf", - srcs: ["override_bpf.c"], + name: "overrideBpf", + srcs: ["overrideBpf.c"], } prebuilt_etc { @@ -6305,7 +6305,7 @@ func TestOverrideApex(t *testing.T) { ensureContains(t, copyCmds, "image.apex/app/override_app@TEST.BUILD_ID/override_app.apk") ensureNotContains(t, copyCmds, "image.apex/etc/bpf/bpf.o") - ensureContains(t, copyCmds, "image.apex/etc/bpf/override_bpf.o") + ensureContains(t, copyCmds, "image.apex/etc/bpf/overrideBpf.o") ensureNotContains(t, copyCmds, "image.apex/etc/myetc") ensureContains(t, copyCmds, "image.apex/etc/override_myetc") @@ -6339,7 +6339,7 @@ func TestOverrideApex(t *testing.T) { data.Custom(&builder, name, "TARGET_", "", data) androidMk := builder.String() ensureContains(t, androidMk, "LOCAL_MODULE := override_app.override_myapex") - ensureContains(t, androidMk, "LOCAL_MODULE := override_bpf.o.override_myapex") + ensureContains(t, androidMk, "LOCAL_MODULE := overrideBpf.o.override_myapex") ensureContains(t, androidMk, "LOCAL_MODULE := apex_manifest.pb.override_myapex") ensureContains(t, androidMk, "LOCAL_MODULE := override_bcplib.override_myapex") ensureContains(t, androidMk, "LOCAL_MODULE := override_systemserverlib.override_myapex") diff --git a/apex/bp2build.go b/apex/bp2build.go new file mode 100644 index 000000000..221ab132f --- /dev/null +++ b/apex/bp2build.go @@ -0,0 +1,30 @@ +// Copyright (C) 2022 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 apex + +import ( + "android/soong/android" + "strings" +) + +// This file contains the bp2build integration for the apex package. + +// Export constants as Starlark using bp2build to Bazel. +func BazelApexToolchainVars() string { + content := []string{ + "# GENERATED BY SOONG. DO NOT EDIT.", + "default_manifest_version = " + android.DefaultUpdatableModuleVersion, // constants.go is different in every branch. + } + return strings.Join(content, "\n") +} diff --git a/apex/builder.go b/apex/builder.go index 1956b4447..f1b14484e 100644 --- a/apex/builder.go +++ b/apex/builder.go @@ -214,7 +214,7 @@ func (a *apexBundle) buildManifest(ctx android.ModuleContext, provideNativeLibs, Args: map[string]string{ "provideNativeLibs": strings.Join(provideNativeLibs, " "), "requireNativeLibs": strings.Join(requireNativeLibs, " "), - "default_version": defaultManifestVersion, + "default_version": android.DefaultUpdatableModuleVersion, "opt": strings.Join(optCommands, " "), }, }) @@ -549,8 +549,6 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { outHostBinDir := ctx.Config().HostToolPath(ctx, "").String() prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin") - // Figure out if we need to compress the apex. - compressionEnabled := ctx.Config().CompressedApex() && proptools.BoolDefault(a.overridableProperties.Compressible, false) && !a.testApex && !ctx.Config().UnbundledBuildApps() if apexType == imageApex { //////////////////////////////////////////////////////////////////////////////////// @@ -635,10 +633,15 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { implicitInputs = append(implicitInputs, noticeAssetPath) optFlags = append(optFlags, "--assets_dir "+filepath.Dir(noticeAssetPath.String())) - if (moduleMinSdkVersion.GreaterThan(android.SdkVersion_Android10) && !a.shouldGenerateHashtree()) && !compressionEnabled { - // Apexes which are supposed to be installed in builtin dirs(/system, etc) - // don't need hashtree for activation. Therefore, by removing hashtree from - // apex bundle (filesystem image in it, to be specific), we can save storage. + // Apexes which are supposed to be installed in builtin dirs(/system, etc) + // don't need hashtree for activation. Therefore, by removing hashtree from + // apex bundle (filesystem image in it, to be specific), we can save storage. + needHashTree := moduleMinSdkVersion.LessThanOrEqualTo(android.SdkVersion_Android10) || + a.shouldGenerateHashtree() + if ctx.Config().ApexCompressionEnabled() && a.isCompressable() { + needHashTree = true + } + if !needHashTree { optFlags = append(optFlags, "--no_hashtree") } @@ -806,8 +809,9 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { return } - if apexType == imageApex && (compressionEnabled || a.testOnlyShouldForceCompression()) { - a.isCompressed = true + installSuffix := suffix + a.setCompression(ctx) + if a.isCompressed { unsignedCompressedOutputFile := android.PathForModuleOut(ctx, a.Name()+imageCapexSuffix+".unsigned") compressRule := android.NewRuleBuilder(pctx, ctx) @@ -835,10 +839,6 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { Args: args, }) a.outputFile = signedCompressedOutputFile - } - - installSuffix := suffix - if a.isCompressed { installSuffix = imageCapexSuffix } diff --git a/apex/vndk_test.go b/apex/vndk_test.go index d580e5aa6..21526c3eb 100644 --- a/apex/vndk_test.go +++ b/apex/vndk_test.go @@ -86,7 +86,6 @@ func TestVndkApexUsesVendorVariant(t *testing.T) { }, system_shared_libs: [], stl: "none", - notice: "custom_notice", } ` + vndkLibrariesTxtFiles("current") diff --git a/bazel/aquery.go b/bazel/aquery.go index ae2b107e1..418b14321 100644 --- a/bazel/aquery.go +++ b/bazel/aquery.go @@ -574,7 +574,7 @@ func (a *aqueryArtifactHandler) getOutputPaths(actionEntry action) (outputPaths // expandTemplateContent substitutes the tokens in a template. func expandTemplateContent(actionEntry action) string { - replacerString := []string{} + var replacerString []string for _, pair := range actionEntry.Substitutions { value := pair.Value if val, ok := templateActionOverriddenTokens[pair.Key]; ok { @@ -647,7 +647,7 @@ func expandPathFragment(id pathFragmentId, pathFragmentsMap map[pathFragmentId]p } labels = append([]string{currFragment.Label}, labels...) if currId == currFragment.ParentId { - return "", fmt.Errorf("Fragment cannot refer to itself as parent %#v", currFragment) + return "", fmt.Errorf("fragment cannot refer to itself as parent %#v", currFragment) } currId = currFragment.ParentId } diff --git a/bazel/aquery_test.go b/bazel/aquery_test.go index 3a2bf0f38..53056c742 100644 --- a/bazel/aquery_test.go +++ b/bazel/aquery_test.go @@ -499,19 +499,11 @@ func TestSymlinkTree(t *testing.T) { func TestBazelOutRemovalFromInputDepsets(t *testing.T) { const inputString = `{ - "artifacts": [{ - "id": 1, - "pathFragmentId": 10 - }, { - "id": 2, - "pathFragmentId": 20 - }, { - "id": 3, - "pathFragmentId": 30 - }, { - "id": 4, - "pathFragmentId": 40 - }], + "artifacts": [ + { "id": 1, "pathFragmentId": 10 }, + { "id": 2, "pathFragmentId": 20 }, + { "id": 3, "pathFragmentId": 30 }, + { "id": 4, "pathFragmentId": 40 }], "depSetOfFiles": [{ "id": 1111, "directArtifactIds": [3 , 4] @@ -525,28 +517,14 @@ func TestBazelOutRemovalFromInputDepsets(t *testing.T) { "outputIds": [2], "primaryOutputId": 1 }], - "pathFragments": [{ - "id": 10, - "label": "input" - }, { - "id": 20, - "label": "output" - }, { - "id": 30, - "label": "dep1", - "parentId": 50 - }, { - "id": 40, - "label": "dep2", - "parentId": 60 - }, { - "id": 50, - "label": "bazel_tools", - "parentId": 60 - }, { - "id": 60, - "label": ".." - }] + "pathFragments": [ + { "id": 10, "label": "input" }, + { "id": 20, "label": "output" }, + { "id": 30, "label": "dep1", "parentId": 50 }, + { "id": 40, "label": "dep2", "parentId": 60 }, + { "id": 50, "label": "bazel_tools", "parentId": 60 }, + { "id": 60, "label": ".."} + ] }` actualBuildStatements, actualDepsets, _ := AqueryBuildStatements([]byte(inputString)) if len(actualDepsets) != 1 { diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go index f5435f25f..d32e61969 100644 --- a/bazel/cquery/request_type.go +++ b/bazel/cquery/request_type.go @@ -1,6 +1,7 @@ package cquery import ( + "encoding/json" "fmt" "strings" ) @@ -9,6 +10,7 @@ var ( GetOutputFiles = &getOutputFilesRequestType{} GetPythonBinary = &getPythonBinaryRequestType{} GetCcInfo = &getCcInfoType{} + GetApexInfo = &getApexInfoType{} ) type CcInfo struct { @@ -179,7 +181,7 @@ func (g getCcInfoType) ParseResult(rawString string) (CcInfo, error) { const expectedLen = 10 splitString := strings.Split(rawString, "|") if len(splitString) != expectedLen { - return CcInfo{}, fmt.Errorf("Expected %d items, got %q", expectedLen, splitString) + return CcInfo{}, fmt.Errorf("expected %d items, got %q", expectedLen, splitString) } outputFilesString := splitString[0] ccObjectsString := splitString[1] @@ -215,6 +217,54 @@ func (g getCcInfoType) ParseResult(rawString string) (CcInfo, error) { }, nil } +// Query Bazel for the artifacts generated by the apex modules. +type getApexInfoType struct{} + +// Name returns a string name for this request type. Such request type names must be unique, +// and must only consist of alphanumeric characters. +func (g getApexInfoType) Name() string { + return "getApexInfo" +} + +// StarlarkFunctionBody returns a starlark function body to process this request type. +// The returned string is the body of a Starlark function which obtains +// all request-relevant information about a target and returns a string containing +// this information. The function should have the following properties: +// - `target` is the only parameter to this function (a configured target). +// - The return value must be a string. +// - The function body should not be indented outside of its own scope. +func (g getApexInfoType) StarlarkFunctionBody() string { + return `info = providers(target)["//build/bazel/rules/apex:apex.bzl%ApexInfo"] +return "{%s}" % ",".join([ + json_for_file("signed_output", info.signed_output), + json_for_file("unsigned_output", info.unsigned_output), + json_for_labels("provides_native_libs", info.provides_native_libs), + json_for_labels("requires_native_libs", info.requires_native_libs), + json_for_files("bundle_key_pair", info.bundle_key_pair), + json_for_files("container_key_pair", info.container_key_pair) + ])` +} + +type ApexCqueryInfo struct { + SignedOutput string `json:"signed_output"` + UnsignedOutput string `json:"unsigned_output"` + ProvidesLibs []string `json:"provides_native_libs"` + RequiresLibs []string `json:"requires_native_libs"` + BundleKeyPair []string `json:"bundle_key_pair"` + ContainerKeyPair []string `json:"container_key_pair"` +} + +// ParseResult returns a value obtained by parsing the result of the request's Starlark function. +// The given rawString must correspond to the string output which was created by evaluating the +// Starlark given in StarlarkFunctionBody. +func (g getApexInfoType) ParseResult(rawString string) ApexCqueryInfo { + var info ApexCqueryInfo + if err := json.Unmarshal([]byte(rawString), &info); err != nil { + panic(fmt.Errorf("cannot parse cquery result '%s': %s", rawString, err)) + } + return info +} + // splitOrEmpty is a modification of strings.Split() that returns an empty list // if the given string is empty. func splitOrEmpty(s string, sep string) []string { diff --git a/bazel/cquery/request_type_test.go b/bazel/cquery/request_type_test.go index 606e285bb..34248ce81 100644 --- a/bazel/cquery/request_type_test.go +++ b/bazel/cquery/request_type_test.go @@ -148,13 +148,13 @@ func TestGetCcInfoParseResults(t *testing.T) { description: "too few result splits", input: "|", expectedOutput: CcInfo{}, - expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", expectedSplits, []string{"", ""}), + expectedErrorMessage: fmt.Sprintf("expected %d items, got %q", expectedSplits, []string{"", ""}), }, { description: "too many result splits", input: strings.Repeat("|", expectedSplits+1), // 2 too many expectedOutput: CcInfo{}, - expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", expectedSplits, make([]string, expectedSplits+2)), + expectedErrorMessage: fmt.Sprintf("expected %d items, got %q", expectedSplits, make([]string, expectedSplits+2)), }, } for _, tc := range testCases { @@ -167,3 +167,40 @@ func TestGetCcInfoParseResults(t *testing.T) { } } } + +func TestGetApexInfoParseResults(t *testing.T) { + testCases := []struct { + description string + input string + expectedOutput ApexCqueryInfo + }{ + { + description: "no result", + input: "{}", + expectedOutput: ApexCqueryInfo{}, + }, + { + description: "one result", + input: `{"signed_output":"my.apex",` + + `"unsigned_output":"my.apex.unsigned",` + + `"requires_native_libs":["//bionic/libc:libc","//bionic/libdl:libdl"],` + + `"bundle_key_pair":["foo.pem","foo.privkey"],` + + `"container_key_pair":["foo.x509.pem", "foo.pk8"],` + + `"provides_native_libs":[]}`, + expectedOutput: ApexCqueryInfo{ + SignedOutput: "my.apex", + UnsignedOutput: "my.apex.unsigned", + RequiresLibs: []string{"//bionic/libc:libc", "//bionic/libdl:libdl"}, + ProvidesLibs: []string{}, + BundleKeyPair: []string{"foo.pem", "foo.privkey"}, + ContainerKeyPair: []string{"foo.x509.pem", "foo.pk8"}, + }, + }, + } + for _, tc := range testCases { + actualOutput := GetApexInfo.ParseResult(tc.input) + if !reflect.DeepEqual(tc.expectedOutput, actualOutput) { + t.Errorf("%q: expected %#v != actual %#v", tc.description, tc.expectedOutput, actualOutput) + } + } +} diff --git a/bp2build/Android.bp b/bp2build/Android.bp index 34548ed95..07557d604 100644 --- a/bp2build/Android.bp +++ b/bp2build/Android.bp @@ -20,15 +20,16 @@ bootstrap_go_package { "soong-android", "soong-android-allowlists", "soong-android-soongconfig", - "soong-shared", "soong-apex", "soong-bazel", "soong-cc", "soong-cc-config", "soong-etc", "soong-genrule", + "soong-linkerconfig", "soong-python", "soong-sh", + "soong-shared", "soong-starlark-format", "soong-ui-metrics", ], @@ -58,6 +59,7 @@ bootstrap_go_package { "java_library_host_conversion_test.go", "java_plugin_conversion_test.go", "java_proto_conversion_test.go", + "linker_config_conversion_test.go", "performance_test.go", "prebuilt_etc_conversion_test.go", "python_binary_conversion_test.go", diff --git a/bp2build/bp2build.go b/bp2build/bp2build.go index b0c3899ba..0e3d2a5f9 100644 --- a/bp2build/bp2build.go +++ b/bp2build/bp2build.go @@ -29,7 +29,9 @@ import ( func Codegen(ctx *CodegenContext) CodegenMetrics { // This directory stores BUILD files that could be eventually checked-in. bp2buildDir := android.PathForOutput(ctx, "bp2build") - android.RemoveAllOutputDir(bp2buildDir) + if err := android.RemoveAllOutputDir(bp2buildDir); err != nil { + fmt.Printf("ERROR: Encountered error while cleaning %s: %s", bp2buildDir, err.Error()) + } res, errs := GenerateBazelTargets(ctx, true) if len(errs) > 0 { @@ -40,7 +42,7 @@ func Codegen(ctx *CodegenContext) CodegenMetrics { fmt.Printf("ERROR: Encountered %d error(s): \nERROR: %s", len(errs), strings.Join(errMsgs, "\n")) os.Exit(1) } - bp2buildFiles := CreateBazelFiles(nil, res.buildFileToTargets, ctx.mode) + bp2buildFiles := CreateBazelFiles(ctx.Config(), nil, res.buildFileToTargets, ctx.mode) writeFiles(ctx, bp2buildDir, bp2buildFiles) soongInjectionDir := android.PathForOutput(ctx, bazel.SoongInjectionDirName) @@ -52,7 +54,9 @@ func Codegen(ctx *CodegenContext) CodegenMetrics { // Get the output directory and create it if it doesn't exist. func getOrCreateOutputDir(outputDir android.OutputPath, ctx android.PathContext, dir string) android.OutputPath { dirPath := outputDir.Join(ctx, dir) - android.CreateOutputDirIfNonexistent(dirPath, os.ModePerm) + if err := android.CreateOutputDirIfNonexistent(dirPath, os.ModePerm); err != nil { + fmt.Printf("ERROR: path %s: %s", dirPath, err.Error()) + } return dirPath } @@ -60,13 +64,13 @@ func getOrCreateOutputDir(outputDir android.OutputPath, ctx android.PathContext, func writeFiles(ctx android.PathContext, outputDir android.OutputPath, files []BazelFile) { for _, f := range files { p := getOrCreateOutputDir(outputDir, ctx, f.Dir).Join(ctx, f.Basename) - if err := writeFile(ctx, p, f.Contents); err != nil { + if err := writeFile(p, f.Contents); err != nil { panic(fmt.Errorf("Failed to write %q (dir %q) due to %q", f.Basename, f.Dir, err)) } } } -func writeFile(ctx android.PathContext, pathToFile android.OutputPath, content string) error { +func writeFile(pathToFile android.OutputPath, content string) error { // These files are made editable to allow users to modify and iterate on them // in the source tree. return android.WriteFileToOutputDir(pathToFile, []byte(content), 0644) diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go index a96a3fc7b..415becb84 100644 --- a/bp2build/build_conversion.go +++ b/bp2build/build_conversion.go @@ -161,22 +161,22 @@ type CodegenContext struct { unconvertedDepMode unconvertedDepsMode } -func (c *CodegenContext) Mode() CodegenMode { - return c.mode +func (ctx *CodegenContext) Mode() CodegenMode { + return ctx.mode } // CodegenMode is an enum to differentiate code-generation modes. type CodegenMode int const ( - // Bp2Build: generate BUILD files with targets buildable by Bazel directly. + // Bp2Build - generate BUILD files with targets buildable by Bazel directly. // // This mode is used for the Soong->Bazel build definition conversion. Bp2Build CodegenMode = iota - // QueryView: generate BUILD files with targets representing fully mutated + // QueryView - generate BUILD files with targets representing fully mutated // Soong modules, representing the fully configured Soong module graph with - // variants and dependency endges. + // variants and dependency edges. // // This mode is used for discovering and introspecting the existing Soong // module graph. @@ -470,13 +470,13 @@ func generateSoongModuleTarget(ctx bpToBuildContext, m blueprint.Module) BazelTa }) } - for p, _ := range ignoredPropNames { + for p := range ignoredPropNames { delete(props.Attrs, p) } attributes := propsToAttributes(props.Attrs) depLabelList := "[\n" - for depLabel, _ := range depLabels { + for depLabel := range depLabels { depLabelList += fmt.Sprintf(" %q,\n", depLabel) } depLabelList += " ]" diff --git a/bp2build/bzl_conversion_test.go b/bp2build/bzl_conversion_test.go index f3345a6ae..6cb9509ed 100644 --- a/bp2build/bzl_conversion_test.go +++ b/bp2build/bzl_conversion_test.go @@ -189,7 +189,7 @@ func TestGenerateSoongModuleBzl(t *testing.T) { content: "irrelevant", }, } - files := CreateBazelFiles(ruleShims, make(map[string]BazelTargets), QueryView) + files := CreateBazelFiles(android.NullConfig("out", "out/soong"), ruleShims, make(map[string]BazelTargets), QueryView) var actualSoongModuleBzl BazelFile for _, f := range files { diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go index be096168c..74729e4e1 100644 --- a/bp2build/cc_library_shared_conversion_test.go +++ b/bp2build/cc_library_shared_conversion_test.go @@ -569,3 +569,58 @@ func TestCcLibrarySharedConvertLex(t *testing.T) { }, }) } + +func TestCcLibrarySharedClangUnknownFlags(t *testing.T) { + runCcLibrarySharedTestCase(t, bp2buildTestCase{ + blueprint: soongCcProtoPreamble + `cc_library_shared { + name: "foo", + conlyflags: ["-a", "-finline-functions"], + cflags: ["-b","-finline-functions"], + cppflags: ["-c", "-finline-functions"], + ldflags: ["-d","-finline-functions", "-e"], + include_build_directory: false, +}`, + expectedBazelTargets: []string{ + makeBazelTarget("cc_library_shared", "foo", attrNameToString{ + "conlyflags": `["-a"]`, + "copts": `["-b"]`, + "cppflags": `["-c"]`, + "linkopts": `[ + "-d", + "-e", + ]`, + }), + }, + }) +} + +func TestCCLibraryFlagSpaceSplitting(t *testing.T) { + runCcLibrarySharedTestCase(t, bp2buildTestCase{ + blueprint: soongCcProtoPreamble + `cc_library_shared { + name: "foo", + conlyflags: [ "-include header.h"], + cflags: ["-include header.h"], + cppflags: ["-include header.h"], + version_script: "version_script", + include_build_directory: false, +}`, + expectedBazelTargets: []string{ + makeBazelTarget("cc_library_shared", "foo", attrNameToString{ + "additional_linker_inputs": `["version_script"]`, + "conlyflags": `[ + "-include", + "header.h", + ]`, + "copts": `[ + "-include", + "header.h", + ]`, + "cppflags": `[ + "-include", + "header.h", + ]`, + "linkopts": `["-Wl,--version-script,$(location version_script)"]`, + }), + }, + }) +} diff --git a/bp2build/conversion.go b/bp2build/conversion.go index 4b013d913..8cf9beaf4 100644 --- a/bp2build/conversion.go +++ b/bp2build/conversion.go @@ -10,6 +10,8 @@ import ( cc_config "android/soong/cc/config" java_config "android/soong/java/config" + "android/soong/apex" + "github.com/google/blueprint/proptools" ) @@ -28,6 +30,9 @@ func CreateSoongInjectionFiles(cfg android.Config, metrics CodegenMetrics) []Baz files = append(files, newFile("java_toolchain", GeneratedBuildFileName, "")) // Creates a //java_toolchain package. files = append(files, newFile("java_toolchain", "constants.bzl", java_config.BazelJavaToolchainVars(cfg))) + files = append(files, newFile("apex_toolchain", GeneratedBuildFileName, "")) // Creates a //apex_toolchain package. + files = append(files, newFile("apex_toolchain", "constants.bzl", apex.BazelApexToolchainVars())) + files = append(files, newFile("metrics", "converted_modules.txt", strings.Join(metrics.convertedModules, "\n"))) files = append(files, newFile("product_config", "soong_config_variables.bzl", cfg.Bp2buildSoongConfigDefinitions.String())) @@ -50,6 +55,7 @@ func convertedModules(convertedModules []string) string { } func CreateBazelFiles( + cfg android.Config, ruleShims map[string]RuleShim, buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile { @@ -74,16 +80,19 @@ func CreateBazelFiles( files = append(files, newFile(bazelRulesSubDir, "soong_module.bzl", generateSoongModuleBzl(ruleShims))) } - files = append(files, createBuildFiles(buildToTargets, mode)...) + files = append(files, createBuildFiles(cfg, buildToTargets, mode)...) return files } -func createBuildFiles(buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile { +func createBuildFiles(cfg android.Config, buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile { files := make([]BazelFile, 0, len(buildToTargets)) + warnNotWriting := cfg.IsEnvTrue("BP2BUILD_VERBOSE") for _, dir := range android.SortedStringKeys(buildToTargets) { if mode == Bp2Build && android.ShouldKeepExistingBuildFileForDir(dir) { - fmt.Printf("[bp2build] Not writing generated BUILD file for dir: '%s'\n", dir) + if warnNotWriting { + fmt.Printf("[bp2build] Not writing generated BUILD file for dir: '%s'\n", dir) + } continue } targets := buildToTargets[dir] diff --git a/bp2build/conversion_test.go b/bp2build/conversion_test.go index e49d8553b..0cb711ca5 100644 --- a/bp2build/conversion_test.go +++ b/bp2build/conversion_test.go @@ -27,7 +27,8 @@ type bazelFilepath struct { } func TestCreateBazelFiles_QueryView_AddsTopLevelFiles(t *testing.T) { - files := CreateBazelFiles(map[string]RuleShim{}, map[string]BazelTargets{}, QueryView) + files := CreateBazelFiles(android.NullConfig("out", "out/soong"), + map[string]RuleShim{}, map[string]BazelTargets{}, QueryView) expectedFilePaths := []bazelFilepath{ { dir: "", @@ -103,6 +104,14 @@ func TestCreateBazelFiles_Bp2Build_CreatesDefaultFiles(t *testing.T) { basename: "constants.bzl", }, { + dir: "apex_toolchain", + basename: GeneratedBuildFileName, + }, + { + dir: "apex_toolchain", + basename: "constants.bzl", + }, + { dir: "metrics", basename: "converted_modules.txt", }, diff --git a/bp2build/linker_config_conversion_test.go b/bp2build/linker_config_conversion_test.go new file mode 100644 index 000000000..4662af4c1 --- /dev/null +++ b/bp2build/linker_config_conversion_test.go @@ -0,0 +1,59 @@ +// Copyright 2022 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 bp2build + +import ( + "fmt" + "testing" + + "android/soong/linkerconfig" +) + +func runLinkerConfigTestCase(t *testing.T, tc bp2buildTestCase) { + t.Helper() + (&tc).moduleTypeUnderTest = "linker_config" + (&tc).moduleTypeUnderTestFactory = linkerconfig.LinkerConfigFactory + runBp2BuildTestCaseSimple(t, tc) +} + +func TestLinkerConfigConvertsSrc(t *testing.T) { + runLinkerConfigTestCase(t, + bp2buildTestCase{ + blueprint: ` +linker_config { + name: "foo", + src: "a.json", +} +`, + expectedBazelTargets: []string{makeBazelTarget("linker_config", "foo", attrNameToString{ + "src": `"a.json"`, + })}, + }) + +} + +func TestLinkerConfigNoSrc(t *testing.T) { + runLinkerConfigTestCase(t, + bp2buildTestCase{ + blueprint: ` +linker_config { + name: "foo", +} +`, + expectedBazelTargets: []string{}, + expectedErr: fmt.Errorf("Android.bp:2:1: module \"foo\": src: empty src is not supported"), + }) + +} diff --git a/bp2build/metrics.go b/bp2build/metrics.go index 04fac441e..3a21c3454 100644 --- a/bp2build/metrics.go +++ b/bp2build/metrics.go @@ -116,8 +116,6 @@ func (metrics *CodegenMetrics) Write(dir string) { } if _, err := os.Stat(metricsFile); err != nil { fail(err, "MISSING BP2BUILD METRICS OUTPUT: Failed to `stat` %s", metricsFile) - } else { - fmt.Printf("\nWrote bp2build metrics to: %s\n", metricsFile) } } diff --git a/bp2build/symlink_forest.go b/bp2build/symlink_forest.go index 818d7aece..78e7b0e75 100644 --- a/bp2build/symlink_forest.go +++ b/bp2build/symlink_forest.go @@ -1,6 +1,7 @@ package bp2build import ( + "android/soong/android" "fmt" "io/ioutil" "os" @@ -21,7 +22,7 @@ type node struct { children map[string]*node } -// Ensures that the a node for the given path exists in the tree and returns it. +// Ensures that the node for the given path exists in the tree and returns it. func ensureNodeExists(root *node, path string) *node { if path == "" { return root @@ -114,7 +115,7 @@ func isDir(path string, fi os.FileInfo) bool { // contain every file in buildFilesDir and srcDir excluding the files in // exclude. Collects every directory encountered during the traversal of srcDir // into acc. -func plantSymlinkForestRecursive(topdir string, forestDir string, buildFilesDir string, srcDir string, exclude *node, acc *[]string, okay *bool) { +func plantSymlinkForestRecursive(cfg android.Config, topdir string, forestDir string, buildFilesDir string, srcDir string, exclude *node, acc *[]string, okay *bool) { if exclude != nil && exclude.excluded { // This directory is not needed, bail out return @@ -125,11 +126,11 @@ func plantSymlinkForestRecursive(topdir string, forestDir string, buildFilesDir buildFilesMap := readdirToMap(shared.JoinPath(topdir, buildFilesDir)) allEntries := make(map[string]bool) - for n, _ := range srcDirMap { + for n := range srcDirMap { allEntries[n] = true } - for n, _ := range buildFilesMap { + for n := range buildFilesMap { allEntries[n] = true } @@ -139,7 +140,7 @@ func plantSymlinkForestRecursive(topdir string, forestDir string, buildFilesDir os.Exit(1) } - for f, _ := range allEntries { + for f := range allEntries { if f[0] == '.' { continue // Ignore dotfiles } @@ -179,7 +180,7 @@ func plantSymlinkForestRecursive(topdir string, forestDir string, buildFilesDir if bDir && excludeChild != nil { // Not in the source tree, but we have to exclude something from under // this subtree, so descend - plantSymlinkForestRecursive(topdir, forestChild, buildFilesChild, srcChild, excludeChild, acc, okay) + plantSymlinkForestRecursive(cfg, topdir, forestChild, buildFilesChild, srcChild, excludeChild, acc, okay) } else { // Not in the source tree, symlink BUILD file symlinkIntoForest(topdir, forestChild, buildFilesChild) @@ -188,19 +189,21 @@ func plantSymlinkForestRecursive(topdir string, forestDir string, buildFilesDir if sDir && excludeChild != nil { // Not in the build file tree, but we have to exclude something from // under this subtree, so descend - plantSymlinkForestRecursive(topdir, forestChild, buildFilesChild, srcChild, excludeChild, acc, okay) + plantSymlinkForestRecursive(cfg, topdir, forestChild, buildFilesChild, srcChild, excludeChild, acc, okay) } else { // Not in the build file tree, symlink source tree, carry on symlinkIntoForest(topdir, forestChild, srcChild) } } else if sDir && bDir { // Both are directories. Descend. - plantSymlinkForestRecursive(topdir, forestChild, buildFilesChild, srcChild, excludeChild, acc, okay) + plantSymlinkForestRecursive(cfg, topdir, forestChild, buildFilesChild, srcChild, excludeChild, acc, okay) } else if !sDir && !bDir { // Neither is a directory. Prioritize BUILD files generated by bp2build // over any BUILD file imported into external/. - fmt.Fprintf(os.Stderr, "Both '%s' and '%s' exist, symlinking the former to '%s'\n", - buildFilesChild, srcChild, forestChild) + if cfg.IsEnvTrue("BP2BUILD_VERBOSE") { + fmt.Fprintf(os.Stderr, "Both '%s' and '%s' exist, symlinking the former to '%s'\n", + buildFilesChild, srcChild, forestChild) + } symlinkIntoForest(topdir, forestChild, buildFilesChild) } else { // Both exist and one is a file. This is an error. @@ -216,12 +219,12 @@ func plantSymlinkForestRecursive(topdir string, forestDir string, buildFilesDir // "srcDir" while excluding paths listed in "exclude". Returns the set of paths // under srcDir on which readdir() had to be called to produce the symlink // forest. -func PlantSymlinkForest(topdir string, forest string, buildFiles string, srcDir string, exclude []string) []string { +func PlantSymlinkForest(cfg android.Config, topdir string, forest string, buildFiles string, srcDir string, exclude []string) []string { deps := make([]string, 0) os.RemoveAll(shared.JoinPath(topdir, forest)) excludeTree := treeFromExcludePathList(exclude) okay := true - plantSymlinkForestRecursive(topdir, forest, buildFiles, srcDir, excludeTree, &deps, &okay) + plantSymlinkForestRecursive(cfg, topdir, forest, buildFiles, srcDir, excludeTree, &deps, &okay) if !okay { os.Exit(1) } diff --git a/bpf/bpf.go b/bpf/bpf.go index 14b2d84c5..5d2533fc2 100644 --- a/bpf/bpf.go +++ b/bpf/bpf.go @@ -17,6 +17,7 @@ package bpf import ( "fmt" "io" + "path/filepath" "strings" "android/soong/android" @@ -154,6 +155,9 @@ func (bpf *bpf) GenerateAndroidBuildActions(ctx android.ModuleContext) { srcs := android.PathsForModuleSrc(ctx, bpf.properties.Srcs) for _, src := range srcs { + if strings.ContainsRune(filepath.Base(src.String()), '_') { + ctx.ModuleErrorf("invalid character '_' in source name") + } obj := android.ObjPathWithExt(ctx, "unstripped", src, "o") ctx.Build(pctx, android.BuildParams{ diff --git a/bpf/bpf_test.go b/bpf/bpf_test.go index 51fbc15e1..6e3909680 100644 --- a/bpf/bpf_test.go +++ b/bpf/bpf_test.go @@ -30,8 +30,9 @@ var prepareForBpfTest = android.GroupFixturePreparers( cc.PrepareForTestWithCcDefaultModules, android.FixtureMergeMockFs( map[string][]byte{ - "bpf.c": nil, - "BpfTest.cpp": nil, + "bpf.c": nil, + "bpf_invalid_name.c": nil, + "BpfTest.cpp": nil, }, ), PrepareForTestWithBpf, @@ -58,3 +59,15 @@ func TestBpfDataDependency(t *testing.T) { // value is not available for testing from this package. // TODO(jungjw): Add a check for data or move this test to the cc package. } + +func TestBpfSourceName(t *testing.T) { + bp := ` + bpf { + name: "bpf_invalid_name.o", + srcs: ["bpf_invalid_name.c"], + } + ` + prepareForBpfTest.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern( + `\QAndroid.bp:2:3: module "bpf_invalid_name.o" variant "android_common": invalid character '_' in source name\E`)). + RunTestWithBp(t, bp) +} diff --git a/cc/bp2build.go b/cc/bp2build.go index fa30d096b..6cd67330f 100644 --- a/cc/bp2build.go +++ b/cc/bp2build.go @@ -20,6 +20,7 @@ import ( "android/soong/android" "android/soong/bazel" + "android/soong/cc/config" "github.com/google/blueprint" @@ -156,7 +157,7 @@ func bp2buildParseStaticOrSharedProps(ctx android.BazelConversionPathContext, mo attrs := staticOrSharedAttributes{} setAttrs := func(axis bazel.ConfigurationAxis, config string, props StaticOrSharedProperties) { - attrs.Copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, filterOutStdFlag)) + attrs.Copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, true, filterOutStdFlag)) attrs.Srcs.SetSelectValue(axis, config, android.BazelLabelForModuleSrc(ctx, props.Srcs)) attrs.System_dynamic_deps.SetSelectValue(axis, config, bazelLabelForSharedDeps(ctx, props.System_shared_libs)) @@ -326,16 +327,39 @@ func filterOutStdFlag(flag string) bool { return strings.HasPrefix(flag, "-std=") } -func parseCommandLineFlags(soongFlags []string, filterOut filterOutFn) []string { +func filterOutClangUnknownCflags(flag string) bool { + for _, f := range config.ClangUnknownCflags { + if f == flag { + return true + } + } + return false +} + +func parseCommandLineFlags(soongFlags []string, noCoptsTokenization bool, filterOut ...filterOutFn) []string { var result []string for _, flag := range soongFlags { - if filterOut != nil && filterOut(flag) { + skipFlag := false + for _, filter := range filterOut { + if filter != nil && filter(flag) { + skipFlag = true + } + } + if skipFlag { continue } // Soong's cflags can contain spaces, like `-include header.h`. For // Bazel's copts, split them up to be compatible with the // no_copts_tokenization feature. - result = append(result, strings.Split(flag, " ")...) + if noCoptsTokenization { + result = append(result, strings.Split(flag, " ")...) + } else { + // Soong's Version Script and Dynamic List Properties are added as flags + // to Bazel's linkopts using "($location label)" syntax. + // Splitting on spaces would separate this into two different flags + // "($ location" and "label)" + result = append(result, flag) + } } return result } @@ -362,10 +386,10 @@ func (ca *compilerAttributes) bp2buildForAxisAndConfig(ctx android.BazelConversi // overridden. In Bazel we always allow overriding, via flags; however, this can cause // incompatibilities, so we remove "-std=" flags from Cflag properties while leaving it in other // cases. - ca.copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, filterOutStdFlag)) - ca.asFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Asflags, nil)) - ca.conlyFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Conlyflags, nil)) - ca.cppFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Cppflags, nil)) + ca.copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, true, filterOutStdFlag, filterOutClangUnknownCflags)) + ca.asFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Asflags, true, nil)) + ca.conlyFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Conlyflags, true, filterOutClangUnknownCflags)) + ca.cppFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Cppflags, true, filterOutClangUnknownCflags)) ca.rtti.SetSelectValue(axis, config, props.Rtti) } @@ -721,7 +745,7 @@ func (la *linkerAttributes) bp2buildForAxisAndConfig(ctx android.BazelConversion linkerFlags = append(linkerFlags, fmt.Sprintf("-Wl,--dynamic-list,$(location %s)", label.Label)) } - la.linkopts.SetSelectValue(axis, config, linkerFlags) + la.linkopts.SetSelectValue(axis, config, parseCommandLineFlags(linkerFlags, false, filterOutClangUnknownCflags)) la.useLibcrt.SetSelectValue(axis, config, props.libCrt()) if axis == bazel.NoConfigAxis { diff --git a/cc/builder.go b/cc/builder.go index 70bbd6abb..ab2b80a49 100644 --- a/cc/builder.go +++ b/cc/builder.go @@ -63,10 +63,10 @@ var ( ld, ldRE = pctx.RemoteStaticRules("ld", blueprint.RuleParams{ Command: "$reTemplate$ldCmd ${crtBegin} @${out}.rsp " + - "${libFlags} ${crtEnd} -o ${out} ${ldFlags} ${extraLibFlags}", + "${crtEnd} -o ${out} ${ldFlags} ${extraLibFlags}", CommandDeps: []string{"$ldCmd"}, Rspfile: "${out}.rsp", - RspfileContent: "${in}", + RspfileContent: "${in} ${libFlags}", // clang -Wl,--out-implib doesn't update its output file if it hasn't changed. Restat: true, }, diff --git a/cc/config/global.go b/cc/config/global.go index c5fde5560..26d93abb3 100644 --- a/cc/config/global.go +++ b/cc/config/global.go @@ -228,7 +228,6 @@ var ( // New warnings to be fixed after clang-r383902. "-Wno-deprecated-copy", // http://b/153746672 "-Wno-range-loop-construct", // http://b/153747076 - "-Wno-misleading-indentation", // http://b/153746954 "-Wno-zero-as-null-pointer-constant", // http://b/68236239 "-Wno-deprecated-anon-enum-enum-conversion", // http://b/153746485 "-Wno-pessimizing-move", // http://b/154270751 @@ -239,6 +238,8 @@ var ( // New warnings to be fixed after clang-r433403 "-Wno-error=unused-but-set-variable", // http://b/197240255 "-Wno-error=unused-but-set-parameter", // http://b/197240255 + // New warnings to be fixed after clang-r458507 + "-Wno-error=unqualified-std-cast-call", // http://b/239662094 } noOverrideExternalGlobalCflags = []string{ @@ -247,6 +248,8 @@ var ( "-Wno-unused-but-set-parameter", // http://b/215753485 "-Wno-bitwise-instead-of-logical", + // http://b/232926688 + "-Wno-misleading-indentation", } // Extra cflags for external third-party projects to disable warnings that @@ -278,6 +281,12 @@ var ( // http://b/175068488 "-Wno-string-concatenation", + + // http://b/239661264 + "-Wno-deprecated-non-prototype", + } + + llvmNextExtraCommonGlobalCflags = []string{ } IllegalFlags = []string{ @@ -291,8 +300,8 @@ var ( // prebuilts/clang default settings. ClangDefaultBase = "prebuilts/clang/host" - ClangDefaultVersion = "clang-r450784e" - ClangDefaultShortVersion = "14.0.7" + ClangDefaultVersion = "clang-r458507" + ClangDefaultShortVersion = "15.0.1" // Directories with warnings from Android.bp files. WarningAllowedProjects = []string{ @@ -361,6 +370,15 @@ func init() { if ctx.Config().IsEnvTrue("USE_CCACHE") { flags = append(flags, "-Wno-unused-command-line-argument") } + + if ctx.Config().IsEnvTrue("LLVM_NEXT") { + flags = append(flags, llvmNextExtraCommonGlobalCflags...) + } + + if ctx.Config().IsEnvTrue("ALLOW_UNKNOWN_WARNING_OPTION") { + flags = append(flags, "-Wno-error=unknown-warning-option") + } + return strings.Join(flags, " ") }) diff --git a/cc/image.go b/cc/image.go index 3a0857b21..921b2bb13 100644 --- a/cc/image.go +++ b/cc/image.go @@ -533,7 +533,7 @@ func MutateImage(mctx android.BaseModuleContext, m ImageMutatableModule) { } } else { // This is either in /system (or similar: /data), or is a - // modules built with the NDK. Modules built with the NDK + // module built with the NDK. Modules built with the NDK // will be restricted using the existing link type checks. coreVariantNeeded = true } diff --git a/cc/library.go b/cc/library.go index c445a42ca..bd6ccb5b5 100644 --- a/cc/library.go +++ b/cc/library.go @@ -1032,9 +1032,19 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa ctx.PropertyErrorf("symbol_file", "%q doesn't have .map.txt suffix", symbolFile) return Objects{} } + // b/239274367 --apex and --systemapi filters symbols tagged with # apex and # + // systemapi, respectively. The former is for symbols defined in platform libraries + // and the latter is for symbols defined in APEXes. + var flag string + if ctx.Module().(android.ApexModule).NotInPlatform() { + flag = "--apex" + } else { + // TODO(b/239274367) drop --apex when #apex is replaced with #systemapi + // in the map.txt files of platform libraries + flag = "--systemapi --apex" + } nativeAbiResult := parseNativeAbiDefinition(ctx, symbolFile, - android.ApiLevelOrPanic(ctx, library.MutatedProperties.StubsVersion), - "--apex") + android.ApiLevelOrPanic(ctx, library.MutatedProperties.StubsVersion), flag) objs := compileStubLibrary(ctx, flags, nativeAbiResult.stubSrc) library.versionScriptPath = android.OptionalPathForPath( nativeAbiResult.versionScript) @@ -1584,10 +1594,10 @@ func (library *libraryDecorator) coverageOutputFilePath() android.OptionalPath { func getRefAbiDumpFile(ctx ModuleContext, vndkVersion, fileName string) android.Path { // The logic must be consistent with classifySourceAbiDump. isNdk := ctx.isNdk(ctx.Config()) - isLlndkOrVndk := ctx.IsLlndkPublic() || (ctx.useVndk() && ctx.isVndk()) + isVndk := ctx.useVndk() && ctx.isVndk() - refAbiDumpTextFile := android.PathForVndkRefAbiDump(ctx, vndkVersion, fileName, isNdk, isLlndkOrVndk, false) - refAbiDumpGzipFile := android.PathForVndkRefAbiDump(ctx, vndkVersion, fileName, isNdk, isLlndkOrVndk, true) + refAbiDumpTextFile := android.PathForVndkRefAbiDump(ctx, vndkVersion, fileName, isNdk, isVndk, false) + refAbiDumpGzipFile := android.PathForVndkRefAbiDump(ctx, vndkVersion, fileName, isNdk, isVndk, true) if refAbiDumpTextFile.Valid() { if refAbiDumpGzipFile.Valid() { diff --git a/cc/ndk_api_coverage_parser/__init__.py b/cc/ndk_api_coverage_parser/__init__.py index 8b9cd66fa..752f7d488 100755 --- a/cc/ndk_api_coverage_parser/__init__.py +++ b/cc/ndk_api_coverage_parser/__init__.py @@ -23,6 +23,7 @@ import sys from xml.etree.ElementTree import Element, SubElement, tostring from symbolfile import ( ALL_ARCHITECTURES, + Filter, FUTURE_API_LEVEL, MultiplyDefinedSymbolError, SymbolFileParser, @@ -139,9 +140,8 @@ def main(): with open(args.symbol_file) as symbol_file: try: - versions = SymbolFileParser( - symbol_file, api_map, "", FUTURE_API_LEVEL, True, True - ).parse() + filt = Filter("", FUTURE_API_LEVEL, True, True, True) + versions = SymbolFileParser(symbol_file, api_map, filt).parse() except MultiplyDefinedSymbolError as ex: sys.exit('{}: error: {}'.format(args.symbol_file, ex)) diff --git a/cc/ndk_api_coverage_parser/test_ndk_api_coverage_parser.py b/cc/ndk_api_coverage_parser/test_ndk_api_coverage_parser.py index 141059c7d..7c6ef682b 100644 --- a/cc/ndk_api_coverage_parser/test_ndk_api_coverage_parser.py +++ b/cc/ndk_api_coverage_parser/test_ndk_api_coverage_parser.py @@ -20,7 +20,7 @@ import textwrap import unittest from xml.etree.ElementTree import fromstring -from symbolfile import FUTURE_API_LEVEL, SymbolFileParser +from symbolfile import Filter, FUTURE_API_LEVEL, SymbolFileParser import ndk_api_coverage_parser as nparser @@ -78,9 +78,8 @@ class ApiCoverageSymbolFileParserTest(unittest.TestCase): """ ) ) - parser = SymbolFileParser( - input_file, {}, "", FUTURE_API_LEVEL, True, True - ) + filt = Filter("", FUTURE_API_LEVEL, True, True, True) + parser = SymbolFileParser(input_file, {}, filt) generator = nparser.XmlGenerator(io.StringIO()) result = generator.convertToXml(parser.parse()) expected = fromstring( diff --git a/cc/ndkstubgen/__init__.py b/cc/ndkstubgen/__init__.py index 5e6b8f509..f893d41e2 100755 --- a/cc/ndkstubgen/__init__.py +++ b/cc/ndkstubgen/__init__.py @@ -29,15 +29,12 @@ from symbolfile import Arch, Version class Generator: """Output generator that writes stub source files and version scripts.""" def __init__(self, src_file: TextIO, version_script: TextIO, - symbol_list: TextIO, arch: Arch, api: int, llndk: bool, - apex: bool) -> None: + symbol_list: TextIO, filt: symbolfile.Filter) -> None: self.src_file = src_file self.version_script = version_script self.symbol_list = symbol_list - self.arch = arch - self.api = api - self.llndk = llndk - self.apex = apex + self.filter = filt + self.api = filt.api def write(self, versions: Iterable[Version]) -> None: """Writes all symbol data to the output files.""" @@ -47,8 +44,7 @@ class Generator: def write_version(self, version: Version) -> None: """Writes a single version block's data to the output files.""" - if symbolfile.should_omit_version(version, self.arch, self.api, - self.llndk, self.apex): + if self.filter.should_omit_version(version): return section_versioned = symbolfile.symbol_versioned_in_api( @@ -56,8 +52,7 @@ class Generator: version_empty = True pruned_symbols = [] for symbol in version.symbols: - if symbolfile.should_omit_symbol(symbol, self.arch, self.api, - self.llndk, self.apex): + if self.filter.should_omit_symbol(symbol): continue if symbolfile.symbol_versioned_in_api(symbol.tags, self.api): @@ -110,12 +105,12 @@ def parse_args() -> argparse.Namespace: parser.add_argument( '--apex', action='store_true', - help='Use the APEX variant. Note: equivalent to --system-api.') + help='Use the APEX variant.') parser.add_argument( - '--system-api', + '--systemapi', action='store_true', - dest='apex', - help='Use the SystemAPI variant. Note: equivalent to --apex.') + dest='systemapi', + help='Use the SystemAPI variant.') parser.add_argument('--api-map', type=resolved_path, @@ -152,11 +147,10 @@ def main() -> None: verbosity = 2 logging.basicConfig(level=verbose_map[verbosity]) + filt = symbolfile.Filter(args.arch, api, args.llndk, args.apex, args.systemapi) with args.symbol_file.open() as symbol_file: try: - versions = symbolfile.SymbolFileParser(symbol_file, api_map, - args.arch, api, args.llndk, - args.apex).parse() + versions = symbolfile.SymbolFileParser(symbol_file, api_map, filt).parse() except symbolfile.MultiplyDefinedSymbolError as ex: sys.exit(f'{args.symbol_file}: error: {ex}') @@ -164,7 +158,7 @@ def main() -> None: with args.version_script.open('w') as version_script: with args.symbol_list.open('w') as symbol_list: generator = Generator(src_file, version_script, symbol_list, - args.arch, api, args.llndk, args.apex) + filt) generator.write(versions) diff --git a/cc/ndkstubgen/test_ndkstubgen.py b/cc/ndkstubgen/test_ndkstubgen.py index c8cd056a4..450719bfc 100755 --- a/cc/ndkstubgen/test_ndkstubgen.py +++ b/cc/ndkstubgen/test_ndkstubgen.py @@ -18,6 +18,7 @@ import io import textwrap import unittest +from copy import copy import symbolfile from symbolfile import Arch, Tags @@ -29,6 +30,9 @@ import ndkstubgen class GeneratorTest(unittest.TestCase): + def setUp(self) -> None: + self.filter = symbolfile.Filter(Arch('arm'), 9, False, False) + def test_omit_version(self) -> None: # Thorough testing of the cases involved here is handled by # OmitVersionTest, PrivateVersionTest, and SymbolPresenceTest. @@ -37,7 +41,7 @@ class GeneratorTest(unittest.TestCase): symbol_list_file = io.StringIO() generator = ndkstubgen.Generator(src_file, version_file, symbol_list_file, - Arch('arm'), 9, False, False) + self.filter) version = symbolfile.Version('VERSION_PRIVATE', None, Tags(), [ symbolfile.Symbol('foo', Tags()), @@ -70,7 +74,7 @@ class GeneratorTest(unittest.TestCase): symbol_list_file = io.StringIO() generator = ndkstubgen.Generator(src_file, version_file, symbol_list_file, - Arch('arm'), 9, False, False) + self.filter) version = symbolfile.Version('VERSION_1', None, Tags(), [ symbolfile.Symbol('foo', Tags.from_strs(['x86'])), @@ -106,7 +110,7 @@ class GeneratorTest(unittest.TestCase): symbol_list_file = io.StringIO() generator = ndkstubgen.Generator(src_file, version_file, symbol_list_file, - Arch('arm'), 9, False, False) + self.filter) versions = [ symbolfile.Version('VERSION_1', None, Tags(), [ @@ -162,6 +166,9 @@ class GeneratorTest(unittest.TestCase): class IntegrationTest(unittest.TestCase): + def setUp(self) -> None: + self.filter = symbolfile.Filter(Arch('arm'), 9, False, False) + def test_integration(self) -> None: api_map = { 'O': 9000, @@ -199,8 +206,7 @@ class IntegrationTest(unittest.TestCase): wobble; } VERSION_4; """)) - parser = symbolfile.SymbolFileParser(input_file, api_map, Arch('arm'), - 9, False, False) + parser = symbolfile.SymbolFileParser(input_file, api_map, self.filter) versions = parser.parse() src_file = io.StringIO() @@ -208,7 +214,7 @@ class IntegrationTest(unittest.TestCase): symbol_list_file = io.StringIO() generator = ndkstubgen.Generator(src_file, version_file, symbol_list_file, - Arch('arm'), 9, False, False) + self.filter) generator.write(versions) expected_src = textwrap.dedent("""\ @@ -263,16 +269,18 @@ class IntegrationTest(unittest.TestCase): *; }; """)) - parser = symbolfile.SymbolFileParser(input_file, api_map, Arch('arm'), - 9001, False, False) + f = copy(self.filter) + f.api = 9001 + parser = symbolfile.SymbolFileParser(input_file, api_map, f) versions = parser.parse() src_file = io.StringIO() version_file = io.StringIO() symbol_list_file = io.StringIO() + f = copy(self.filter) + f.api = 9001 generator = ndkstubgen.Generator(src_file, - version_file, symbol_list_file, - Arch('arm'), 9001, False, False) + version_file, symbol_list_file, f) generator.write(versions) expected_src = textwrap.dedent("""\ @@ -322,8 +330,9 @@ class IntegrationTest(unittest.TestCase): } VERSION_2; """)) - parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, - False, False) + f = copy(self.filter) + f.api = 16 + parser = symbolfile.SymbolFileParser(input_file, {}, f) with self.assertRaises( symbolfile.MultiplyDefinedSymbolError) as ex_context: @@ -370,16 +379,18 @@ class IntegrationTest(unittest.TestCase): wobble; } VERSION_4; """)) - parser = symbolfile.SymbolFileParser(input_file, api_map, Arch('arm'), - 9, False, True) + f = copy(self.filter) + f.apex = True + parser = symbolfile.SymbolFileParser(input_file, api_map, f) versions = parser.parse() src_file = io.StringIO() version_file = io.StringIO() symbol_list_file = io.StringIO() + f = copy(self.filter) + f.apex = True generator = ndkstubgen.Generator(src_file, - version_file, symbol_list_file, - Arch('arm'), 9, False, True) + version_file, symbol_list_file, f) generator.write(versions) expected_src = textwrap.dedent("""\ @@ -428,20 +439,19 @@ class IntegrationTest(unittest.TestCase): *; }; """)) - parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), - 9, llndk=False, apex=True) + f = copy(self.filter) + f.apex = True + parser = symbolfile.SymbolFileParser(input_file, {}, f) versions = parser.parse() src_file = io.StringIO() version_file = io.StringIO() symbol_list_file = io.StringIO() + f = copy(self.filter) + f.apex = True generator = ndkstubgen.Generator(src_file, version_file, - symbol_list_file, - Arch('arm'), - 9, - llndk=False, - apex=True) + symbol_list_file, f) generator.write(versions) self.assertEqual('', src_file.getvalue()) diff --git a/cc/symbolfile/__init__.py b/cc/symbolfile/__init__.py index f8d18414c..471a12f50 100644 --- a/cc/symbolfile/__init__.py +++ b/cc/symbolfile/__init__.py @@ -78,12 +78,17 @@ class Tags: @property def has_mode_tags(self) -> bool: """Returns True if any mode tags (apex, llndk, etc) are set.""" - return self.has_apex_tags or self.has_llndk_tags + return self.has_apex_tags or self.has_llndk_tags or self.has_systemapi_tags @property def has_apex_tags(self) -> bool: """Returns True if any APEX tags are set.""" - return 'apex' in self.tags or 'systemapi' in self.tags + return 'apex' in self.tags + + @property + def has_systemapi_tags(self) -> bool: + """Returns True if any APEX tags are set.""" + return 'systemapi' in self.tags @property def has_llndk_tags(self) -> bool: @@ -198,50 +203,57 @@ def get_tag_value(tag: Tag) -> str: """ return split_tag(tag)[1] +class Filter: + """A filter encapsulates a condition that tells whether a version or a + symbol should be omitted or not + """ -def _should_omit_tags(tags: Tags, arch: Arch, api: int, llndk: bool, - apex: bool) -> bool: - """Returns True if the tagged object should be omitted. + def __init__(self, arch: Arch, api: int, llndk: bool = False, apex: bool = False, systemapi: bool = False): + self.arch = arch + self.api = api + self.llndk = llndk + self.apex = apex + self.systemapi = systemapi - This defines the rules shared between version tagging and symbol tagging. - """ - # The apex and llndk tags will only exclude APIs from other modes. If in - # APEX or LLNDK mode and neither tag is provided, we fall back to the - # default behavior because all NDK symbols are implicitly available to APEX - # and LLNDK. - if tags.has_mode_tags: - if not apex and not llndk: + def _should_omit_tags(self, tags: Tags) -> bool: + """Returns True if the tagged object should be omitted. + + This defines the rules shared between version tagging and symbol tagging. + """ + # The apex and llndk tags will only exclude APIs from other modes. If in + # APEX or LLNDK mode and neither tag is provided, we fall back to the + # default behavior because all NDK symbols are implicitly available to + # APEX and LLNDK. + if tags.has_mode_tags: + if self.apex and tags.has_apex_tags: + return False + if self.llndk and tags.has_llndk_tags: + return False + if self.systemapi and tags.has_systemapi_tags: + return False return True - if apex and not tags.has_apex_tags: + if not symbol_in_arch(tags, self.arch): return True - if llndk and not tags.has_llndk_tags: + if not symbol_in_api(tags, self.arch, self.api): return True - if not symbol_in_arch(tags, arch): - return True - if not symbol_in_api(tags, arch, api): - return True - return False - + return False -def should_omit_version(version: Version, arch: Arch, api: int, llndk: bool, - apex: bool) -> bool: - """Returns True if the version section should be omitted. - - We want to omit any sections that do not have any symbols we'll have in the - stub library. Sections that contain entirely future symbols or only symbols - for certain architectures. - """ - if version.is_private: - return True - if version.tags.has_platform_only_tags: - return True - return _should_omit_tags(version.tags, arch, api, llndk, apex) + def should_omit_version(self, version: Version) -> bool: + """Returns True if the version section should be omitted. + We want to omit any sections that do not have any symbols we'll have in + the stub library. Sections that contain entirely future symbols or only + symbols for certain architectures. + """ + if version.is_private: + return True + if version.tags.has_platform_only_tags: + return True + return self._should_omit_tags(version.tags) -def should_omit_symbol(symbol: Symbol, arch: Arch, api: int, llndk: bool, - apex: bool) -> bool: - """Returns True if the symbol should be omitted.""" - return _should_omit_tags(symbol.tags, arch, api, llndk, apex) + def should_omit_symbol(self, symbol: Symbol) -> bool: + """Returns True if the symbol should be omitted.""" + return self._should_omit_tags(symbol.tags) def symbol_in_arch(tags: Tags, arch: Arch) -> bool: @@ -316,14 +328,10 @@ class MultiplyDefinedSymbolError(RuntimeError): class SymbolFileParser: """Parses NDK symbol files.""" - def __init__(self, input_file: TextIO, api_map: ApiMap, arch: Arch, - api: int, llndk: bool, apex: bool) -> None: + def __init__(self, input_file: TextIO, api_map: ApiMap, filt: Filter) -> None: self.input_file = input_file self.api_map = api_map - self.arch = arch - self.api = api - self.llndk = llndk - self.apex = apex + self.filter = filt self.current_line: Optional[str] = None def parse(self) -> List[Version]: @@ -352,13 +360,11 @@ class SymbolFileParser: symbol_names = set() multiply_defined_symbols = set() for version in versions: - if should_omit_version(version, self.arch, self.api, self.llndk, - self.apex): + if self.filter.should_omit_version(version): continue for symbol in version.symbols: - if should_omit_symbol(symbol, self.arch, self.api, self.llndk, - self.apex): + if self.filter.should_omit_symbol(symbol): continue if symbol.name in symbol_names: diff --git a/cc/symbolfile/test_symbolfile.py b/cc/symbolfile/test_symbolfile.py index c1e821904..e17a8d01d 100644 --- a/cc/symbolfile/test_symbolfile.py +++ b/cc/symbolfile/test_symbolfile.py @@ -19,7 +19,8 @@ import textwrap import unittest import symbolfile -from symbolfile import Arch, Tag, Tags, Version +from symbolfile import Arch, Tag, Tags, Version, Symbol, Filter +from copy import copy # pylint: disable=missing-docstring @@ -202,178 +203,188 @@ class SymbolPresenceTest(unittest.TestCase): class OmitVersionTest(unittest.TestCase): + def setUp(self) -> None: + self.filter = Filter(arch = Arch('arm'), api = 9) + self.version = Version('foo', None, Tags(), []) + + def assertOmit(self, f: Filter, v: Version) -> None: + self.assertTrue(f.should_omit_version(v)) + + def assertInclude(self, f: Filter, v: Version) -> None: + self.assertFalse(f.should_omit_version(v)) + def test_omit_private(self) -> None: - self.assertFalse( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, Tags(), []), Arch('arm'), 9, - False, False)) + f = self.filter + v = self.version - self.assertTrue( - symbolfile.should_omit_version( - symbolfile.Version('foo_PRIVATE', None, Tags(), []), - Arch('arm'), 9, False, False)) - self.assertTrue( - symbolfile.should_omit_version( - symbolfile.Version('foo_PLATFORM', None, Tags(), []), - Arch('arm'), 9, False, False)) + self.assertInclude(f, v) - self.assertTrue( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, - Tags.from_strs(['platform-only']), []), - Arch('arm'), 9, False, False)) + v.name = 'foo_PRIVATE' + self.assertOmit(f, v) + + v.name = 'foo_PLATFORM' + self.assertOmit(f, v) + + v.name = 'foo' + v.tags = Tags.from_strs(['platform-only']) + self.assertOmit(f, v) def test_omit_llndk(self) -> None: - self.assertTrue( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, Tags.from_strs(['llndk']), []), - Arch('arm'), 9, False, False)) + f = self.filter + v = self.version + v_llndk = copy(v) + v_llndk.tags = Tags.from_strs(['llndk']) - self.assertFalse( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, Tags(), []), Arch('arm'), 9, - True, False)) - self.assertFalse( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, Tags.from_strs(['llndk']), []), - Arch('arm'), 9, True, False)) + self.assertOmit(f, v_llndk) + + f.llndk = True + self.assertInclude(f, v) + self.assertInclude(f, v_llndk) def test_omit_apex(self) -> None: - self.assertTrue( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, Tags.from_strs(['apex']), []), - Arch('arm'), 9, False, False)) + f = self.filter + v = self.version + v_apex = copy(v) + v_apex.tags = Tags.from_strs(['apex']) + v_systemapi = copy(v) + v_systemapi.tags = Tags.from_strs(['systemapi']) - self.assertFalse( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, Tags(), []), Arch('arm'), 9, - False, True)) - self.assertFalse( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, Tags.from_strs(['apex']), []), - Arch('arm'), 9, False, True)) + self.assertOmit(f, v_apex) + + f.apex = True + self.assertInclude(f, v) + self.assertInclude(f, v_apex) + self.assertOmit(f, v_systemapi) def test_omit_systemapi(self) -> None: - self.assertTrue( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, Tags.from_strs(['systemapi']), - []), Arch('arm'), 9, False, False)) + f = self.filter + v = self.version + v_apex = copy(v) + v_apex.tags = Tags.from_strs(['apex']) + v_systemapi = copy(v) + v_systemapi.tags = Tags.from_strs(['systemapi']) - self.assertFalse( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, Tags(), []), Arch('arm'), 9, - False, True)) - self.assertFalse( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, Tags.from_strs(['systemapi']), - []), Arch('arm'), 9, False, True)) + self.assertOmit(f, v_systemapi) + + f.systemapi = True + self.assertInclude(f, v) + self.assertInclude(f, v_systemapi) + self.assertOmit(f, v_apex) def test_omit_arch(self) -> None: - self.assertFalse( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, Tags(), []), Arch('arm'), 9, - False, False)) - self.assertFalse( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, Tags.from_strs(['arm']), []), - Arch('arm'), 9, False, False)) + f_arm = self.filter + v_none = self.version + self.assertInclude(f_arm, v_none) - self.assertTrue( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, Tags.from_strs(['x86']), []), - Arch('arm'), 9, False, False)) + v_arm = copy(v_none) + v_arm.tags = Tags.from_strs(['arm']) + self.assertInclude(f_arm, v_arm) + + v_x86 = copy(v_none) + v_x86.tags = Tags.from_strs(['x86']) + self.assertOmit(f_arm, v_x86) def test_omit_api(self) -> None: - self.assertFalse( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, Tags(), []), Arch('arm'), 9, - False, False)) - self.assertFalse( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, - Tags.from_strs(['introduced=9']), []), - Arch('arm'), 9, False, False)) + f_api9 = self.filter + v_none = self.version + self.assertInclude(f_api9, v_none) - self.assertTrue( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, - Tags.from_strs(['introduced=14']), []), - Arch('arm'), 9, False, False)) + v_api9 = copy(v_none) + v_api9.tags = Tags.from_strs(['introduced=9']) + self.assertInclude(f_api9, v_api9) + + v_api14 = copy(v_none) + v_api14.tags = Tags.from_strs(['introduced=14']) + self.assertOmit(f_api9, v_api14) class OmitSymbolTest(unittest.TestCase): + def setUp(self) -> None: + self.filter = Filter(arch = Arch('arm'), api = 9) + + def assertOmit(self, f: Filter, s: Symbol) -> None: + self.assertTrue(f.should_omit_symbol(s)) + + def assertInclude(self, f: Filter, s: Symbol) -> None: + self.assertFalse(f.should_omit_symbol(s)) + def test_omit_llndk(self) -> None: - self.assertTrue( - symbolfile.should_omit_symbol( - symbolfile.Symbol('foo', Tags.from_strs(['llndk'])), - Arch('arm'), 9, False, False)) + f_none = self.filter + f_llndk = copy(f_none) + f_llndk.llndk = True - self.assertFalse( - symbolfile.should_omit_symbol(symbolfile.Symbol('foo', Tags()), - Arch('arm'), 9, True, False)) - self.assertFalse( - symbolfile.should_omit_symbol( - symbolfile.Symbol('foo', Tags.from_strs(['llndk'])), - Arch('arm'), 9, True, False)) + s_none = Symbol('foo', Tags()) + s_llndk = Symbol('foo', Tags.from_strs(['llndk'])) + + self.assertOmit(f_none, s_llndk) + self.assertInclude(f_llndk, s_none) + self.assertInclude(f_llndk, s_llndk) def test_omit_apex(self) -> None: - self.assertTrue( - symbolfile.should_omit_symbol( - symbolfile.Symbol('foo', Tags.from_strs(['apex'])), - Arch('arm'), 9, False, False)) + f_none = self.filter + f_apex = copy(f_none) + f_apex.apex = True - self.assertFalse( - symbolfile.should_omit_symbol(symbolfile.Symbol('foo', Tags()), - Arch('arm'), 9, False, True)) - self.assertFalse( - symbolfile.should_omit_symbol( - symbolfile.Symbol('foo', Tags.from_strs(['apex'])), - Arch('arm'), 9, False, True)) + s_none = Symbol('foo', Tags()) + s_apex = Symbol('foo', Tags.from_strs(['apex'])) + s_systemapi = Symbol('foo', Tags.from_strs(['systemapi'])) - def test_omit_systemapi(self) -> None: - self.assertTrue( - symbolfile.should_omit_symbol( - symbolfile.Symbol('foo', Tags.from_strs(['systemapi'])), - Arch('arm'), 9, False, False)) + self.assertOmit(f_none, s_apex) + self.assertInclude(f_apex, s_none) + self.assertInclude(f_apex, s_apex) + self.assertOmit(f_apex, s_systemapi) - self.assertFalse( - symbolfile.should_omit_symbol(symbolfile.Symbol('foo', Tags()), - Arch('arm'), 9, False, True)) - self.assertFalse( - symbolfile.should_omit_symbol( - symbolfile.Symbol('foo', Tags.from_strs(['systemapi'])), - Arch('arm'), 9, False, True)) + def test_omit_systemapi(self) -> None: + f_none = self.filter + f_systemapi = copy(f_none) + f_systemapi.systemapi = True + + s_none = Symbol('foo', Tags()) + s_apex = Symbol('foo', Tags.from_strs(['apex'])) + s_systemapi = Symbol('foo', Tags.from_strs(['systemapi'])) + + self.assertOmit(f_none, s_systemapi) + self.assertInclude(f_systemapi, s_none) + self.assertInclude(f_systemapi, s_systemapi) + self.assertOmit(f_systemapi, s_apex) + + def test_omit_apex_and_systemapi(self) -> None: + f = self.filter + f.systemapi = True + f.apex = True + + s_none = Symbol('foo', Tags()) + s_apex = Symbol('foo', Tags.from_strs(['apex'])) + s_systemapi = Symbol('foo', Tags.from_strs(['systemapi'])) + self.assertInclude(f, s_none) + self.assertInclude(f, s_apex) + self.assertInclude(f, s_systemapi) def test_omit_arch(self) -> None: - self.assertFalse( - symbolfile.should_omit_symbol(symbolfile.Symbol('foo', Tags()), - Arch('arm'), 9, False, False)) - self.assertFalse( - symbolfile.should_omit_symbol( - symbolfile.Symbol('foo', Tags.from_strs(['arm'])), Arch('arm'), - 9, False, False)) + f_arm = self.filter + s_none = Symbol('foo', Tags()) + s_arm = Symbol('foo', Tags.from_strs(['arm'])) + s_x86 = Symbol('foo', Tags.from_strs(['x86'])) - self.assertTrue( - symbolfile.should_omit_symbol( - symbolfile.Symbol('foo', Tags.from_strs(['x86'])), Arch('arm'), - 9, False, False)) + self.assertInclude(f_arm, s_none) + self.assertInclude(f_arm, s_arm) + self.assertOmit(f_arm, s_x86) def test_omit_api(self) -> None: - self.assertFalse( - symbolfile.should_omit_symbol(symbolfile.Symbol('foo', Tags()), - Arch('arm'), 9, False, False)) - self.assertFalse( - symbolfile.should_omit_symbol( - symbolfile.Symbol('foo', Tags.from_strs(['introduced=9'])), - Arch('arm'), 9, False, False)) + f_api9 = self.filter + s_none = Symbol('foo', Tags()) + s_api9 = Symbol('foo', Tags.from_strs(['introduced=9'])) + s_api14 = Symbol('foo', Tags.from_strs(['introduced=14'])) - self.assertTrue( - symbolfile.should_omit_symbol( - symbolfile.Symbol('foo', Tags.from_strs(['introduced=14'])), - Arch('arm'), 9, False, False)) + self.assertInclude(f_api9, s_none) + self.assertInclude(f_api9, s_api9) + self.assertOmit(f_api9, s_api14) class SymbolFileParseTest(unittest.TestCase): + def setUp(self) -> None: + self.filter = Filter(arch = Arch('arm'), api = 16) + def test_next_line(self) -> None: input_file = io.StringIO(textwrap.dedent("""\ foo @@ -382,8 +393,7 @@ class SymbolFileParseTest(unittest.TestCase): # baz qux """)) - parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, - False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, self.filter) self.assertIsNone(parser.current_line) self.assertEqual('foo', parser.next_line().strip()) @@ -409,8 +419,7 @@ class SymbolFileParseTest(unittest.TestCase): VERSION_2 { } VERSION_1; # asdf """)) - parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, - False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, self.filter) parser.next_line() version = parser.parse_version() @@ -419,8 +428,8 @@ class SymbolFileParseTest(unittest.TestCase): self.assertEqual(Tags.from_strs(['foo', 'bar']), version.tags) expected_symbols = [ - symbolfile.Symbol('baz', Tags()), - symbolfile.Symbol('qux', Tags.from_strs(['woodly', 'doodly'])), + Symbol('baz', Tags()), + Symbol('qux', Tags.from_strs(['woodly', 'doodly'])), ] self.assertEqual(expected_symbols, version.symbols) @@ -434,8 +443,7 @@ class SymbolFileParseTest(unittest.TestCase): input_file = io.StringIO(textwrap.dedent("""\ VERSION_1 { """)) - parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, - False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, self.filter) parser.next_line() with self.assertRaises(symbolfile.ParseError): parser.parse_version() @@ -446,8 +454,7 @@ class SymbolFileParseTest(unittest.TestCase): foo: } """)) - parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, - False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, self.filter) parser.next_line() with self.assertRaises(symbolfile.ParseError): parser.parse_version() @@ -457,8 +464,7 @@ class SymbolFileParseTest(unittest.TestCase): foo; bar; # baz qux """)) - parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, - False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, self.filter) parser.next_line() symbol = parser.parse_symbol() @@ -476,8 +482,7 @@ class SymbolFileParseTest(unittest.TestCase): *; }; """)) - parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, - False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, self.filter) parser.next_line() with self.assertRaises(symbolfile.ParseError): parser.parse_version() @@ -489,8 +494,7 @@ class SymbolFileParseTest(unittest.TestCase): *; }; """)) - parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, - False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, self.filter) parser.next_line() version = parser.parse_version() self.assertEqual([], version.symbols) @@ -501,8 +505,7 @@ class SymbolFileParseTest(unittest.TestCase): foo }; """)) - parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, - False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, self.filter) parser.next_line() with self.assertRaises(symbolfile.ParseError): parser.parse_version() @@ -510,8 +513,7 @@ class SymbolFileParseTest(unittest.TestCase): def test_parse_fails_invalid_input(self) -> None: with self.assertRaises(symbolfile.ParseError): input_file = io.StringIO('foo') - parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), - 16, False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, self.filter) parser.parse() def test_parse(self) -> None: @@ -532,19 +534,18 @@ class SymbolFileParseTest(unittest.TestCase): qwerty; } VERSION_1; """)) - parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, - False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, self.filter) versions = parser.parse() expected = [ symbolfile.Version('VERSION_1', None, Tags(), [ - symbolfile.Symbol('foo', Tags()), - symbolfile.Symbol('bar', Tags.from_strs(['baz'])), + Symbol('foo', Tags()), + Symbol('bar', Tags.from_strs(['baz'])), ]), symbolfile.Version( 'VERSION_2', 'VERSION_1', Tags.from_strs(['wasd']), [ - symbolfile.Symbol('woodly', Tags()), - symbolfile.Symbol('doodly', Tags.from_strs(['asdf'])), + Symbol('woodly', Tags()), + Symbol('doodly', Tags.from_strs(['asdf'])), ]), ] @@ -559,8 +560,9 @@ class SymbolFileParseTest(unittest.TestCase): qux; # apex }; """)) - parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, - False, True) + f = copy(self.filter) + f.llndk = True + parser = symbolfile.SymbolFileParser(input_file, {}, f) parser.next_line() version = parser.parse_version() @@ -568,10 +570,10 @@ class SymbolFileParseTest(unittest.TestCase): self.assertIsNone(version.base) expected_symbols = [ - symbolfile.Symbol('foo', Tags()), - symbolfile.Symbol('bar', Tags.from_strs(['llndk'])), - symbolfile.Symbol('baz', Tags.from_strs(['llndk', 'apex'])), - symbolfile.Symbol('qux', Tags.from_strs(['apex'])), + Symbol('foo', Tags()), + Symbol('bar', Tags.from_strs(['llndk'])), + Symbol('baz', Tags.from_strs(['llndk', 'apex'])), + Symbol('qux', Tags.from_strs(['apex'])), ] self.assertEqual(expected_symbols, version.symbols) diff --git a/cc/testing.go b/cc/testing.go index 6b858d593..d70ec9bb5 100644 --- a/cc/testing.go +++ b/cc/testing.go @@ -194,7 +194,6 @@ func commonDefaultModules() string { native_coverage: false, system_shared_libs: [], stl: "none", - notice: "custom_notice", } cc_library { name: "libprofile-clang-extras", @@ -205,7 +204,6 @@ func commonDefaultModules() string { native_coverage: false, system_shared_libs: [], stl: "none", - notice: "custom_notice", } cc_library { name: "libprofile-extras_ndk", @@ -214,7 +212,6 @@ func commonDefaultModules() string { native_coverage: false, system_shared_libs: [], stl: "none", - notice: "custom_notice", sdk_version: "current", } cc_library { @@ -224,7 +221,6 @@ func commonDefaultModules() string { native_coverage: false, system_shared_libs: [], stl: "none", - notice: "custom_notice", sdk_version: "current", } diff --git a/cc/vndk.go b/cc/vndk.go index bf6148b1c..4cd4d4273 100644 --- a/cc/vndk.go +++ b/cc/vndk.go @@ -671,12 +671,8 @@ func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContex snapshotArchDir := filepath.Join(snapshotDir, ctx.DeviceConfig().DeviceArch()) configsDir := filepath.Join(snapshotArchDir, "configs") - noticeDir := filepath.Join(snapshotArchDir, "NOTICE_FILES") includeDir := filepath.Join(snapshotArchDir, "include") - // set of notice files copied. - noticeBuilt := make(map[string]bool) - // paths of VNDK modules for GPL license checking modulePaths := make(map[string]string) @@ -762,16 +758,6 @@ func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContex moduleNames[stem] = ctx.ModuleName(m) modulePaths[stem] = ctx.ModuleDir(m) - if len(m.NoticeFiles()) > 0 { - noticeName := stem + ".txt" - // skip already copied notice file - if _, ok := noticeBuilt[noticeName]; !ok { - noticeBuilt[noticeName] = true - snapshotOutputs = append(snapshotOutputs, combineNoticesRule( - ctx, m.NoticeFiles(), filepath.Join(noticeDir, noticeName))) - } - } - if ctx.Config().VndkSnapshotBuildArtifacts() { headers = append(headers, m.SnapshotHeaders()...) } diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go index 8a3d6e037..53422cd6c 100644 --- a/cmd/soong_build/main.go +++ b/cmd/soong_build/main.go @@ -220,7 +220,7 @@ func writeDepFile(outputFile string, eventHandler metrics.EventHandler, ninjaDep // doChosenActivity runs Soong for a specific activity, like bp2build, queryview // or the actual Soong build for the build.ninja file. Returns the top level // output file of the specific activity. -func doChosenActivity(configuration android.Config, extraNinjaDeps []string, logDir string) string { +func doChosenActivity(ctx *android.Context, configuration android.Config, extraNinjaDeps []string, logDir string) string { mixedModeBuild := configuration.BazelContext.BazelEnabled() generateBazelWorkspace := bp2buildMarker != "" generateQueryView := bazelQueryViewDir != "" @@ -236,7 +236,6 @@ func doChosenActivity(configuration android.Config, extraNinjaDeps []string, log blueprintArgs := cmdlineArgs - ctx := newContext(configuration) if mixedModeBuild { runMixedModeBuild(configuration, ctx, extraNinjaDeps) } else { @@ -284,7 +283,6 @@ func doChosenActivity(configuration android.Config, extraNinjaDeps []string, log } } - writeMetrics(configuration, *ctx.EventHandler, logDir) return cmdlineArgs.OutFile } @@ -344,7 +342,13 @@ func main() { // change between every CI build, so tracking it would require re-running Soong for every build. logDir := availableEnv["LOG_DIR"] - finalOutputFile := doChosenActivity(configuration, extraNinjaDeps, logDir) + ctx := newContext(configuration) + ctx.EventHandler.Begin("soong_build") + + finalOutputFile := doChosenActivity(ctx, configuration, extraNinjaDeps, logDir) + + ctx.EventHandler.End("soong_build") + writeMetrics(configuration, *ctx.EventHandler, logDir) writeUsedEnvironmentFile(configuration, finalOutputFile) } @@ -552,7 +556,7 @@ func runBp2Build(configuration android.Config, extraNinjaDeps []string) { excludes = append(excludes, getTemporaryExcludes()...) symlinkForestDeps := bp2build.PlantSymlinkForest( - topDir, workspaceRoot, generatedRoot, ".", excludes) + configuration, topDir, workspaceRoot, generatedRoot, ".", excludes) ninjaDeps = append(ninjaDeps, codegenContext.AdditionalNinjaDeps()...) ninjaDeps = append(ninjaDeps, symlinkForestDeps...) @@ -566,7 +570,9 @@ func runBp2Build(configuration android.Config, extraNinjaDeps []string) { // Only report metrics when in bp2build mode. The metrics aren't relevant // for queryview, since that's a total repo-wide conversion and there's a // 1:1 mapping for each module. - metrics.Print() + if configuration.IsEnvTrue("BP2BUILD_VERBOSE") { + metrics.Print() + } writeBp2BuildMetrics(&metrics, configuration, eventHandler) } diff --git a/cmd/soong_build/queryview.go b/cmd/soong_build/queryview.go index d63ded56c..983dbf0fc 100644 --- a/cmd/soong_build/queryview.go +++ b/cmd/soong_build/queryview.go @@ -32,7 +32,8 @@ func createBazelQueryView(ctx *bp2build.CodegenContext, bazelQueryViewDir string panic(err) } - filesToWrite := bp2build.CreateBazelFiles(ruleShims, res.BuildDirToTargets(), bp2build.QueryView) + filesToWrite := bp2build.CreateBazelFiles(ctx.Config(), ruleShims, res.BuildDirToTargets(), + bp2build.QueryView) for _, f := range filesToWrite { if err := writeReadOnlyFile(bazelQueryViewDir, f); err != nil { return err diff --git a/java/aar.go b/java/aar.go index cf84309f4..dadfc6a6f 100644 --- a/java/aar.go +++ b/java/aar.go @@ -893,7 +893,7 @@ func (g *AARImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, return nil } -var _ android.PrebuiltInterface = (*Import)(nil) +var _ android.PrebuiltInterface = (*AARImport)(nil) // android_library_import imports an `.aar` file into the build graph as if it was built with android_library. // diff --git a/java/java.go b/java/java.go index eaf82ad7a..dae69dcdc 100644 --- a/java/java.go +++ b/java/java.go @@ -118,6 +118,16 @@ var ( copyEverythingToSnapshot, } + snapshotRequiresImplementationJar = func(ctx android.SdkMemberContext) bool { + // In the S build the build will break if updatable-media does not provide a full implementation + // jar. That issue was fixed in Tiramisu by b/229932396. + if ctx.IsTargetBuildBeforeTiramisu() && ctx.Name() == "updatable-media" { + return true + } + + return false + } + // Supports adding java boot libraries to module_exports and sdk. // // The build has some implicit dependencies (via the boot jars configuration) on a number of @@ -135,13 +145,21 @@ var ( SupportsSdk: true, }, func(ctx android.SdkMemberContext, j *Library) android.Path { + if snapshotRequiresImplementationJar(ctx) { + return exportImplementationClassesJar(ctx, j) + } + // Java boot libs are only provided in the SDK to provide access to their dex implementation // jar for use by dexpreopting and boot jars package check. They do not need to provide an // actual implementation jar but the java_import will need a file that exists so just copy an // empty file. Any attempt to use that file as a jar will cause a build error. return ctx.SnapshotBuilder().EmptyFile() }, - func(osPrefix, name string) string { + func(ctx android.SdkMemberContext, osPrefix, name string) string { + if snapshotRequiresImplementationJar(ctx) { + return sdkSnapshotFilePathForJar(ctx, osPrefix, name) + } + // Create a special name for the implementation jar to try and provide some useful information // to a developer that attempts to compile against this. // TODO(b/175714559): Provide a proper error message in Soong not ninja. @@ -175,7 +193,7 @@ var ( // file. Any attempt to use that file as a jar will cause a build error. return ctx.SnapshotBuilder().EmptyFile() }, - func(osPrefix, name string) string { + func(_ android.SdkMemberContext, osPrefix, name string) string { // Create a special name for the implementation jar to try and provide some useful information // to a developer that attempts to compile against this. // TODO(b/175714559): Provide a proper error message in Soong not ninja. @@ -672,7 +690,7 @@ const ( ) // path to the jar file of a java library. Relative to <sdk_root>/<api_dir> -func sdkSnapshotFilePathForJar(osPrefix, name string) string { +func sdkSnapshotFilePathForJar(_ android.SdkMemberContext, osPrefix, name string) string { return sdkSnapshotFilePathForMember(osPrefix, name, jarFileSuffix) } @@ -689,7 +707,7 @@ type librarySdkMemberType struct { // Function to compute the snapshot relative path to which the named library's // jar should be copied. - snapshotPathGetter func(osPrefix, name string) string + snapshotPathGetter func(ctx android.SdkMemberContext, osPrefix, name string) string // True if only the jar should be copied to the snapshot, false if the jar plus any additional // files like aidl files should also be copied. @@ -747,7 +765,7 @@ func (p *librarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberConte exportedJar := p.JarToExport if exportedJar != nil { // Delegate the creation of the snapshot relative path to the member type. - snapshotRelativeJavaLibPath := memberType.snapshotPathGetter(p.OsPrefix(), ctx.Name()) + snapshotRelativeJavaLibPath := memberType.snapshotPathGetter(ctx, p.OsPrefix(), ctx.Name()) // Copy the exported jar to the snapshot. builder.CopyToSnapshot(exportedJar, snapshotRelativeJavaLibPath) @@ -1213,7 +1231,7 @@ func (p *testSdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, exportedJar := p.JarToExport if exportedJar != nil { - snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(p.OsPrefix(), ctx.Name()) + snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(ctx, p.OsPrefix(), ctx.Name()) builder.CopyToSnapshot(exportedJar, snapshotRelativeJavaLibPath) propertySet.AddProperty("jars", []string{snapshotRelativeJavaLibPath}) diff --git a/java/lint.go b/java/lint.go index e276345eb..c27ca9821 100644 --- a/java/lint.go +++ b/java/lint.go @@ -338,6 +338,14 @@ func (l *linter) lint(ctx android.ModuleContext) { ctx.PropertyErrorf("lint.disabled_checks", "Can't disable %v checks if min_sdk_version is different from sdk_version.", filtered) } + + // TODO(b/238784089): Remove this workaround when the NewApi issues have been addressed in PermissionController + if ctx.ModuleName() == "PermissionController" { + l.extraMainlineLintErrors = android.FilterListPred(l.extraMainlineLintErrors, func(s string) bool { + return s != "NewApi" + }) + l.properties.Lint.Warning_checks = append(l.properties.Lint.Warning_checks, "NewApi") + } } extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag) diff --git a/java/lint_defaults.txt b/java/lint_defaults.txt index 1eee354cd..e99cb05c5 100644 --- a/java/lint_defaults.txt +++ b/java/lint_defaults.txt @@ -6,6 +6,7 @@ --disable_check AnimatorKeep --disable_check AppBundleLocaleChanges +--disable_check AppCompatCustomView --disable_check BlockedPrivateApi --disable_check CustomSplashScreen --disable_check CustomX509TrustManager @@ -22,6 +23,7 @@ --disable_check PrivateApi --disable_check ProtectedPermissions --disable_check QueryPermissionsNeeded +--disable_check ReservedSystemPermission --disable_check ScopedStorage --disable_check ServiceCast --disable_check SoonBlockedPrivateApi @@ -99,7 +101,10 @@ --warning_check WrongViewCast # 1 occurences in 1 modules --warning_check CoarseFineLocation +--warning_check ExtraText --warning_check IntentFilterExportedReceiver +--warning_check MissingInflatedId +--warning_check NotificationPermission --warning_check QueryAllPackagesPermission --warning_check RemoteViewLayout --warning_check SupportAnnotationUsage diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go index f442ddfd4..1c4249507 100644 --- a/java/platform_compat_config.go +++ b/java/platform_compat_config.go @@ -26,12 +26,14 @@ import ( func init() { registerPlatformCompatConfigBuildComponents(android.InitRegistrationContext) - android.RegisterSdkMemberType(&compatConfigMemberType{ - SdkMemberTypeBase: android.SdkMemberTypeBase{ - PropertyName: "compat_configs", - SupportsSdk: true, - }, - }) + android.RegisterSdkMemberType(CompatConfigSdkMemberType) +} + +var CompatConfigSdkMemberType = &compatConfigMemberType{ + SdkMemberTypeBase: android.SdkMemberTypeBase{ + PropertyName: "compat_configs", + SupportsSdk: true, + }, } func registerPlatformCompatConfigBuildComponents(ctx android.RegistrationContext) { diff --git a/licenses/Android.bp b/licenses/Android.bp index 8db001f44..133f7f783 100644 --- a/licenses/Android.bp +++ b/licenses/Android.bp @@ -32,6 +32,15 @@ license { } license_kind { + name: "BSD-Like-Binary-Only", + conditions: [ + "notice", + "by_exception_only", + "proprietary", + ], +} + +license_kind { name: "SPDX-license-identifier-0BSD", conditions: ["unencumbered"], url: "https://spdx.org/licenses/0BSD", diff --git a/linkerconfig/linkerconfig.go b/linkerconfig/linkerconfig.go index 003b27507..412a23b26 100644 --- a/linkerconfig/linkerconfig.go +++ b/linkerconfig/linkerconfig.go @@ -22,6 +22,7 @@ import ( "github.com/google/blueprint/proptools" "android/soong/android" + "android/soong/bazel" "android/soong/cc" "android/soong/etc" ) @@ -36,7 +37,7 @@ func init() { } func registerLinkerConfigBuildComponent(ctx android.RegistrationContext) { - ctx.RegisterModuleType("linker_config", linkerConfigFactory) + ctx.RegisterModuleType("linker_config", LinkerConfigFactory) } type linkerConfigProperties struct { @@ -52,6 +53,7 @@ type linkerConfigProperties struct { type linkerConfig struct { android.ModuleBase + android.BazelModuleBase properties linkerConfigProperties outputFilePath android.OutputPath @@ -100,6 +102,28 @@ func (l *linkerConfig) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.InstallFile(l.installDirPath, l.outputFilePath.Base(), l.outputFilePath) } +type linkerConfigAttributes struct { + Src bazel.LabelAttribute +} + +func (l *linkerConfig) ConvertWithBp2build(ctx android.TopDownMutatorContext) { + if l.properties.Src == nil { + ctx.PropertyErrorf("src", "empty src is not supported") + return + } + src := android.BazelLabelForModuleSrcSingle(ctx, *l.properties.Src) + targetModuleProperties := bazel.BazelTargetModuleProperties{ + Rule_class: "linker_config", + Bzl_load_location: "//build/bazel/rules:linker_config.bzl", + } + ctx.CreateBazelTargetModule( + targetModuleProperties, + android.CommonAttributes{Name: l.Name()}, + &linkerConfigAttributes{ + Src: bazel.LabelAttribute{Value: &src}, + }) +} + func BuildLinkerConfig(ctx android.ModuleContext, builder *android.RuleBuilder, input android.Path, otherModules []android.Module, output android.OutputPath) { @@ -141,10 +165,11 @@ func BuildLinkerConfig(ctx android.ModuleContext, builder *android.RuleBuilder, // linker_config generates protobuf file from json file. This protobuf file will be used from // linkerconfig while generating ld.config.txt. Format of this file can be found from // https://android.googlesource.com/platform/system/linkerconfig/+/master/README.md -func linkerConfigFactory() android.Module { +func LinkerConfigFactory() android.Module { m := &linkerConfig{} m.AddProperties(&m.properties) android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibFirst) + android.InitBazelModule(m) return m } diff --git a/rust/OWNERS b/rust/OWNERS index ddaebc522..b59551160 100644 --- a/rust/OWNERS +++ b/rust/OWNERS @@ -1,5 +1,2 @@ # Additional owner/reviewers for rust rules, including parent directory owners. per-file * = chiw@google.com, chriswailes@google.com, ivanlozano@google.com, jeffv@google.com, mmaurer@google.com, srhines@google.com - -# Limited owners/reviewers of the allowed list. -per-file allowed_list.go = chiw@google.com, chriswailes@google.com, ivanlozano@google.com, jeffv@google.com, mmaurer@google.com, srhines@google.com diff --git a/rust/bindgen.go b/rust/bindgen.go index 4d723d6a6..72cc894cc 100644 --- a/rust/bindgen.go +++ b/rust/bindgen.go @@ -239,6 +239,11 @@ func (b *bindgenDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) andr cflags = append(cflags, "-x c") } + // LLVM_NEXT may contain flags that bindgen doesn't recognise. Turn off unknown flags warning. + if ctx.Config().IsEnvTrue("LLVM_NEXT") { + cflags = append(cflags, "-Wno-unknown-warning-option") + } + outputFile := android.PathForModuleOut(ctx, b.BaseSourceProvider.getStem(ctx)+".rs") var cmd, cmdDesc string diff --git a/rust/config/Android.bp b/rust/config/Android.bp index ba40cb0a6..be73d69eb 100644 --- a/rust/config/Android.bp +++ b/rust/config/Android.bp @@ -16,7 +16,6 @@ bootstrap_go_package { "global.go", "lints.go", "toolchain.go", - "allowed_list.go", "darwin_host.go", "x86_linux_bionic_host.go", "x86_linux_host.go", diff --git a/rust/config/allowed_list.go b/rust/config/allowed_list.go deleted file mode 100644 index 9129b0e10..000000000 --- a/rust/config/allowed_list.go +++ /dev/null @@ -1,79 +0,0 @@ -package config - -var ( - // When adding a new path below, add a rustfmt.toml file at the root of - // the repository and enable the rustfmt repo hook. See aosp/1458238 - // for an example. - // TODO(b/160223496): enable rustfmt globally. - RustAllowedPaths = []string{ - "device/google/cuttlefish", - "external/adhd", - "external/boringssl", - "external/crosvm", - "external/libchromeos-rs", - "external/minijail", - "external/open-dice", - "external/rust", - "external/selinux/libselinux", - "external/uwb", - "external/vm_tools/p9", - "frameworks/native/libs/binder/rust", - "frameworks/proto_logging/stats", - "hardware/interfaces/security", - "hardware/interfaces/uwb", - "packages/modules/Bluetooth", - "packages/modules/DnsResolver", - "packages/modules/Uwb", - "packages/modules/Virtualization", - "platform_testing/tests/codecoverage/native/rust", - "prebuilts/rust", - "system/core/debuggerd/rust", - "system/core/libstats/pull_rust", - "system/core/trusty/libtrusty-rs", - "system/core/trusty/keymint", - "system/extras/profcollectd", - "system/extras/simpleperf", - "system/hardware/interfaces/keystore2", - "system/keymint", - "system/librustutils", - "system/logging/liblog", - "system/logging/rust", - "system/nfc", - "system/security", - "system/tools/aidl", - "tools/security/fuzzing/example_rust_fuzzer", - "tools/security/fuzzing/orphans", - "tools/security/remote_provisioning/cert_validator", - "tools/vendor", - "vendor/", - } - - DownstreamRustAllowedPaths = []string{ - // Add downstream allowed Rust paths here. - } - - RustModuleTypes = []string{ - // Don't add rust_bindgen or rust_protobuf as these are code generation modules - // and can be expected to be in paths without Rust code. - "rust_benchmark", - "rust_benchmark_host", - "rust_binary", - "rust_binary_host", - "rust_library", - "rust_library_dylib", - "rust_library_rlib", - "rust_ffi", - "rust_ffi_shared", - "rust_ffi_static", - "rust_fuzz", - "rust_library_host", - "rust_library_host_dylib", - "rust_library_host_rlib", - "rust_ffi_host", - "rust_ffi_host_shared", - "rust_ffi_host_static", - "rust_proc_macro", - "rust_test", - "rust_test_host", - } -) diff --git a/rust/config/global.go b/rust/config/global.go index 9e48344b8..9acbfb355 100644 --- a/rust/config/global.go +++ b/rust/config/global.go @@ -24,7 +24,7 @@ import ( var pctx = android.NewPackageContext("android/soong/rust/config") var ( - RustDefaultVersion = "1.62.0" + RustDefaultVersion = "1.62.0.p1" RustDefaultBase = "prebuilts/rust/" DefaultEdition = "2021" Stdlibs = []string{ diff --git a/rust/rust.go b/rust/rust.go index d5d492971..4d9fe4c03 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -33,13 +33,6 @@ import ( var pctx = android.NewPackageContext("android/soong/rust") func init() { - // Only allow rust modules to be defined for certain projects - - android.AddNeverAllowRules( - android.NeverAllow(). - NotIn(append(config.RustAllowedPaths, config.DownstreamRustAllowedPaths...)...). - ModuleType(config.RustModuleTypes...)) - android.RegisterModuleType("rust_defaults", defaultsFactory) android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) { ctx.BottomUp("rust_libraries", LibraryMutator).Parallel() diff --git a/sdk/build_release.go b/sdk/build_release.go index 4c2277e85..0494a28ee 100644 --- a/sdk/build_release.go +++ b/sdk/build_release.go @@ -24,18 +24,22 @@ import ( // buildRelease represents the version of a build system used to create a specific release. // -// The name of the release, is the same as the code for the dessert release, e.g. S, T, etc. +// The name of the release, is the same as the code for the dessert release, e.g. S, Tiramisu, etc. type buildRelease struct { - // The name of the release, e.g. S, T, etc. + // The name of the release, e.g. S, Tiramisu, etc. name string // The index of this structure within the buildReleases list. ordinal int } +func (br *buildRelease) EarlierThan(other *buildRelease) bool { + return br.ordinal < other.ordinal +} + // String returns the name of the build release. -func (s *buildRelease) String() string { - return s.name +func (br *buildRelease) String() string { + return br.name } // buildReleaseSet represents a set of buildRelease objects. diff --git a/sdk/compat_config_sdk_test.go b/sdk/compat_config_sdk_test.go index d166add00..45e8e0ed6 100644 --- a/sdk/compat_config_sdk_test.go +++ b/sdk/compat_config_sdk_test.go @@ -21,16 +21,12 @@ import ( "android/soong/java" ) -func TestSnapshotWithCompatConfig(t *testing.T) { +func testSnapshotWithCompatConfig(t *testing.T, sdk string) { result := android.GroupFixturePreparers( prepareForSdkTestWithJava, java.PrepareForTestWithPlatformCompatConfig, - ).RunTestWithBp(t, ` - sdk { - name: "mysdk", - compat_configs: ["myconfig"], - } - + prepareForSdkTestWithApex, + ).RunTestWithBp(t, sdk+` platform_compat_config { name: "myconfig", } @@ -73,3 +69,28 @@ prebuilt_platform_compat_config { }), ) } + +func TestSnapshotWithCompatConfig(t *testing.T) { + testSnapshotWithCompatConfig(t, ` + sdk { + name: "mysdk", + compat_configs: ["myconfig"], + } +`) +} + +func TestSnapshotWithCompatConfig_Apex(t *testing.T) { + testSnapshotWithCompatConfig(t, ` + apex { + name: "myapex", + key: "myapex.key", + min_sdk_version: "2", + compat_configs: ["myconfig"], + } + + sdk { + name: "mysdk", + apexes: ["myapex"], + } +`) +} diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go index d25138f5b..7ab5285c6 100644 --- a/sdk/java_sdk_test.go +++ b/sdk/java_sdk_test.go @@ -15,6 +15,7 @@ package sdk import ( + "fmt" "testing" "android/soong/android" @@ -257,8 +258,8 @@ func TestSnapshotWithJavaBootLibrary(t *testing.T) { android.FixtureAddFile("aidl", nil), android.FixtureAddFile("resource.txt", nil), ).RunTestWithBp(t, ` - module_exports { - name: "myexports", + sdk { + name: "mysdk", java_boot_libs: ["myjavalib"], } @@ -278,7 +279,7 @@ func TestSnapshotWithJavaBootLibrary(t *testing.T) { } `) - CheckSnapshot(t, result, "myexports", "", + CheckSnapshot(t, result, "mysdk", "", checkAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -292,11 +293,65 @@ java_import { } `), checkAllCopyRules(` -.intermediates/myexports/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/myjavalib.jar +.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/myjavalib.jar `), ) } +func TestSnapshotWithJavaBootLibrary_UpdatableMedia(t *testing.T) { + runTest := func(t *testing.T, targetBuildRelease, expectedJarPath, expectedCopyRule string) { + result := android.GroupFixturePreparers( + prepareForSdkTestWithJava, + android.FixtureMergeEnv(map[string]string{ + "SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE": targetBuildRelease, + }), + ).RunTestWithBp(t, ` + sdk { + name: "mysdk", + java_boot_libs: ["updatable-media"], + } + + java_library { + name: "updatable-media", + srcs: ["Test.java"], + system_modules: "none", + sdk_version: "none", + compile_dex: true, + permitted_packages: ["pkg.media"], + apex_available: ["com.android.media"], + } + `) + + CheckSnapshot(t, result, "mysdk", "", + checkAndroidBpContents(fmt.Sprintf(` +// This is auto-generated. DO NOT EDIT. + +java_import { + name: "updatable-media", + prefer: false, + visibility: ["//visibility:public"], + apex_available: ["com.android.media"], + jars: ["%s"], + permitted_packages: ["pkg.media"], +} +`, expectedJarPath)), + checkAllCopyRules(expectedCopyRule), + ) + } + + t.Run("updatable-media in S", func(t *testing.T) { + runTest(t, "S", "java/updatable-media.jar", ` +.intermediates/updatable-media/android_common/package-check/updatable-media.jar -> java/updatable-media.jar +`) + }) + + t.Run("updatable-media in T", func(t *testing.T) { + runTest(t, "Tiramisu", "java_boot_libs/snapshot/jars/are/invalid/updatable-media.jar", ` +.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/updatable-media.jar +`) + }) +} + func TestSnapshotWithJavaSystemserverLibrary(t *testing.T) { result := android.GroupFixturePreparers( prepareForSdkTestWithJava, @@ -1284,9 +1339,9 @@ java_sdk_library_import { .intermediates/myjavalib.stubs.source.module_lib/android_common/metalava/myjavalib.stubs.source.module_lib_removed.txt -> sdk_library/module-lib/myjavalib-removed.txt `), checkMergeZips( + ".intermediates/mysdk/common_os/tmp/sdk_library/module-lib/myjavalib_stub_sources.zip", ".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip", ".intermediates/mysdk/common_os/tmp/sdk_library/system/myjavalib_stub_sources.zip", - ".intermediates/mysdk/common_os/tmp/sdk_library/module-lib/myjavalib_stub_sources.zip", ), ) } diff --git a/sdk/update.go b/sdk/update.go index b9ef3d0f4..c555ddc7a 100644 --- a/sdk/update.go +++ b/sdk/update.go @@ -108,7 +108,7 @@ var ( mergeZips = pctx.AndroidStaticRule("SnapshotMergeZips", blueprint.RuleParams{ - Command: `${config.MergeZipsCmd} $out $in`, + Command: `${config.MergeZipsCmd} -s $out $in`, CommandDeps: []string{ "${config.MergeZipsCmd}", }, @@ -481,7 +481,7 @@ be unnecessary as every module in the sdk already has its own licenses property. // Copy the build number file into the snapshot. builder.CopyToSnapshot(ctx.Config().BuildNumberFile(ctx), BUILD_NUMBER_FILE) - filesToZip := builder.filesToZip + filesToZip := android.SortedUniquePaths(builder.filesToZip) // zip them all zipPath := fmt.Sprintf("%s%s.zip", ctx.ModuleName(), snapshotFileSuffix) @@ -517,7 +517,7 @@ be unnecessary as every module in the sdk already has its own licenses property. Description: outputDesc, Rule: mergeZips, Input: zipFile, - Inputs: builder.zipsToMerge, + Inputs: android.SortedUniquePaths(builder.zipsToMerge), Output: outputZipFile, }) } @@ -1972,6 +1972,12 @@ func (m *memberContext) RequiresTrait(trait android.SdkMemberTrait) bool { return m.requiredTraits.Contains(trait) } +func (m *memberContext) IsTargetBuildBeforeTiramisu() bool { + return m.builder.targetBuildRelease.EarlierThan(buildReleaseT) +} + +var _ android.SdkMemberContext = (*memberContext)(nil) + func (s *sdk) createMemberSnapshot(ctx *memberContext, member *sdkMember, bpModule *bpModule) { memberType := member.memberType diff --git a/ui/build/build.go b/ui/build/build.go index ec42b7004..5b80b4df8 100644 --- a/ui/build/build.go +++ b/ui/build/build.go @@ -183,8 +183,8 @@ func checkRAM(ctx Context, config Config) { } } -// Build the tree. The 'what' argument can be used to chose which components of -// the build to run, via checking various bitmasks. +// Build the tree. Various flags in `config` govern which components of +// the build to run. func Build(ctx Context, config Config) { ctx.Verboseln("Starting build with args:", config.Arguments()) ctx.Verboseln("Environment:", config.Environment().Environ()) diff --git a/ui/build/cleanbuild.go b/ui/build/cleanbuild.go index 1c80cff31..fd601772c 100644 --- a/ui/build/cleanbuild.go +++ b/ui/build/cleanbuild.go @@ -167,6 +167,7 @@ func installClean(ctx Context, config Config) { productOut("debug_ramdisk"), productOut("vendor_ramdisk"), productOut("vendor_debug_ramdisk"), + productOut("vendor_kernel_ramdisk"), productOut("test_harness_ramdisk"), productOut("recovery"), productOut("root"), diff --git a/ui/build/soong.go b/ui/build/soong.go index 8992b4f07..cfcf99028 100644 --- a/ui/build/soong.go +++ b/ui/build/soong.go @@ -544,7 +544,7 @@ func loadSoongBuildMetrics(ctx Context, config Config) *soong_metrics_proto.Soon buf, err := os.ReadFile(soongBuildMetricsFile) if errors.Is(err, fs.ErrNotExist) { // Soong may not have run during this invocation - ctx.Verbosef("Failed to read metrics file, %s: %s", soongBuildMetricsFile, err) + ctx.Verbosef("Failed to read metrics file, %s: %s", soongBuildMetricsFile, err) return nil } else if err != nil { ctx.Fatalf("Failed to load %s: %s", soongBuildMetricsFile, err) diff --git a/ui/terminal/simple_status.go b/ui/terminal/simple_status.go index cef3b5d5c..9e9ffc003 100644 --- a/ui/terminal/simple_status.go +++ b/ui/terminal/simple_status.go @@ -22,30 +22,24 @@ import ( ) type simpleStatusOutput struct { - writer io.Writer - formatter formatter - keepANSI bool - outputLevel status.MsgLevel + writer io.Writer + formatter formatter + keepANSI bool } // NewSimpleStatusOutput returns a StatusOutput that represents the // current build status similarly to Ninja's built-in terminal // output. -func NewSimpleStatusOutput(w io.Writer, formatter formatter, keepANSI bool, quietBuild bool) status.StatusOutput { - level := status.StatusLvl - if quietBuild { - level = status.PrintLvl - } +func NewSimpleStatusOutput(w io.Writer, formatter formatter, keepANSI bool) status.StatusOutput { return &simpleStatusOutput{ - writer: w, - formatter: formatter, - keepANSI: keepANSI, - outputLevel: level, + writer: w, + formatter: formatter, + keepANSI: keepANSI, } } func (s *simpleStatusOutput) Message(level status.MsgLevel, message string) { - if level >= s.outputLevel { + if level >= status.StatusLvl { output := s.formatter.message(level, message) if !s.keepANSI { output = string(stripAnsiEscapes([]byte(output))) @@ -54,13 +48,10 @@ func (s *simpleStatusOutput) Message(level status.MsgLevel, message string) { } } -func (s *simpleStatusOutput) StartAction(_ *status.Action, _ status.Counts) { +func (s *simpleStatusOutput) StartAction(action *status.Action, counts status.Counts) { } func (s *simpleStatusOutput) FinishAction(result status.ActionResult, counts status.Counts) { - if s.outputLevel > status.StatusLvl { - return - } str := result.Description if str == "" { str = result.Command diff --git a/ui/terminal/status.go b/ui/terminal/status.go index ff0af4737..2ad174fee 100644 --- a/ui/terminal/status.go +++ b/ui/terminal/status.go @@ -29,9 +29,9 @@ import ( func NewStatusOutput(w io.Writer, statusFormat string, forceSimpleOutput, quietBuild, forceKeepANSI bool) status.StatusOutput { formatter := newFormatter(statusFormat, quietBuild) - if forceSimpleOutput || quietBuild || !isSmartTerminal(w) { - return NewSimpleStatusOutput(w, formatter, forceKeepANSI, quietBuild) - } else { + if !forceSimpleOutput && isSmartTerminal(w) { return NewSmartStatusOutput(w, formatter) + } else { + return NewSimpleStatusOutput(w, formatter, forceKeepANSI) } } |