diff options
52 files changed, 1452 insertions, 267 deletions
diff --git a/android/androidmk.go b/android/androidmk.go index d579e30c3..3487b287d 100644 --- a/android/androidmk.go +++ b/android/androidmk.go @@ -46,7 +46,7 @@ type AndroidMkDataProvider interface { type AndroidMkData struct { Class string SubName string - DistFile OptionalPath + DistFiles TaggedDistFiles OutputFile OptionalPath Disabled bool Include string @@ -72,7 +72,7 @@ type AndroidMkEntriesProvider interface { type AndroidMkEntries struct { Class string SubName string - DistFile OptionalPath + DistFiles TaggedDistFiles OutputFile OptionalPath Disabled bool Include string @@ -137,56 +137,112 @@ func (a *AndroidMkEntries) AddStrings(name string, value ...string) { a.EntryMap[name] = append(a.EntryMap[name], value...) } -func (a *AndroidMkEntries) fillInEntries(config Config, bpPath string, mod blueprint.Module) { - a.EntryMap = make(map[string][]string) +// Compute the list of Make strings to declare phone goals and dist-for-goals +// calls from the module's dist and dists properties. +func (a *AndroidMkEntries) GetDistForGoals(mod blueprint.Module) []string { amod := mod.(Module).base() name := amod.BaseModuleName() - if a.Include == "" { - a.Include = "$(BUILD_PREBUILT)" + var ret []string + + availableTaggedDists := TaggedDistFiles{} + if a.DistFiles != nil && len(a.DistFiles[""]) > 0 { + availableTaggedDists = a.DistFiles + } else if a.OutputFile.Valid() { + availableTaggedDists = MakeDefaultDistFiles(a.OutputFile.Path()) } - a.Required = append(a.Required, amod.commonProperties.Required...) - a.Host_required = append(a.Host_required, amod.commonProperties.Host_required...) - a.Target_required = append(a.Target_required, amod.commonProperties.Target_required...) - // Fill in the header part. - if len(amod.commonProperties.Dist.Targets) > 0 { - distFile := a.DistFile - if !distFile.Valid() { - distFile = a.OutputFile + // Iterate over this module's dist structs, merged from the dist and dists properties. + for _, dist := range amod.Dists() { + // Get the list of goals this dist should be enabled for. e.g. sdk, droidcore + goals := strings.Join(dist.Targets, " ") + + // Get the tag representing the output files to be dist'd. e.g. ".jar", ".proguard_map" + var tag string + if dist.Tag == nil { + // If the dist struct does not specify a tag, use the default output files tag. + tag = "" + } else { + tag = *dist.Tag } - if distFile.Valid() { - dest := filepath.Base(distFile.String()) - if amod.commonProperties.Dist.Dest != nil { + // Get the paths of the output files to be dist'd, represented by the tag. + // Can be an empty list. + tagPaths := availableTaggedDists[tag] + if len(tagPaths) == 0 { + // Nothing to dist for this tag, continue to the next dist. + continue + } + + if len(tagPaths) > 1 && (dist.Dest != nil || dist.Suffix != nil) { + errorMessage := "Cannot apply dest/suffix for more than one dist " + + "file for %s goals in module %s. The list of dist files, " + + "which should have a single element, is:\n%s" + panic(fmt.Errorf(errorMessage, goals, name, tagPaths)) + } + + ret = append(ret, fmt.Sprintf(".PHONY: %s\n", goals)) + + // Create dist-for-goals calls for each path in the dist'd files. + for _, path := range tagPaths { + // It's possible that the Path is nil from errant modules. Be defensive here. + if path == nil { + tagName := "default" // for error message readability + if dist.Tag != nil { + tagName = *dist.Tag + } + panic(fmt.Errorf("Dist file should not be nil for the %s tag in %s", tagName, name)) + } + + dest := filepath.Base(path.String()) + + if dist.Dest != nil { var err error - if dest, err = validateSafePath(*amod.commonProperties.Dist.Dest); err != nil { + if dest, err = validateSafePath(*dist.Dest); err != nil { // This was checked in ModuleBase.GenerateBuildActions panic(err) } } - if amod.commonProperties.Dist.Suffix != nil { + if dist.Suffix != nil { ext := filepath.Ext(dest) - suffix := *amod.commonProperties.Dist.Suffix + suffix := *dist.Suffix dest = strings.TrimSuffix(dest, ext) + suffix + ext } - if amod.commonProperties.Dist.Dir != nil { + if dist.Dir != nil { var err error - if dest, err = validateSafePath(*amod.commonProperties.Dist.Dir, dest); err != nil { + if dest, err = validateSafePath(*dist.Dir, dest); err != nil { // This was checked in ModuleBase.GenerateBuildActions panic(err) } } - goals := strings.Join(amod.commonProperties.Dist.Targets, " ") - fmt.Fprintln(&a.header, ".PHONY:", goals) - fmt.Fprintf(&a.header, "$(call dist-for-goals,%s,%s:%s)\n", - goals, distFile.String(), dest) + ret = append( + ret, + fmt.Sprintf("$(call dist-for-goals,%s,%s:%s)\n", goals, path.String(), dest)) } } + return ret +} + +func (a *AndroidMkEntries) fillInEntries(config Config, bpPath string, mod blueprint.Module) { + a.EntryMap = make(map[string][]string) + amod := mod.(Module).base() + name := amod.BaseModuleName() + + if a.Include == "" { + a.Include = "$(BUILD_PREBUILT)" + } + a.Required = append(a.Required, amod.commonProperties.Required...) + a.Host_required = append(a.Host_required, amod.commonProperties.Host_required...) + a.Target_required = append(a.Target_required, amod.commonProperties.Target_required...) + + for _, distString := range a.GetDistForGoals(mod) { + fmt.Fprintf(&a.header, distString) + } + fmt.Fprintln(&a.header, "\ninclude $(CLEAR_VARS)") // Collect make variable assignment entries. @@ -430,7 +486,7 @@ func (data *AndroidMkData) fillInData(config Config, bpPath string, mod blueprin entries := AndroidMkEntries{ Class: data.Class, SubName: data.SubName, - DistFile: data.DistFile, + DistFiles: data.DistFiles, OutputFile: data.OutputFile, Disabled: data.Disabled, Include: data.Include, diff --git a/android/androidmk_test.go b/android/androidmk_test.go index 71f802043..250f086e5 100644 --- a/android/androidmk_test.go +++ b/android/androidmk_test.go @@ -15,6 +15,7 @@ package android import ( + "fmt" "io" "reflect" "testing" @@ -22,10 +23,12 @@ import ( type customModule struct { ModuleBase - data AndroidMkData + data AndroidMkData + distFiles TaggedDistFiles } func (m *customModule) GenerateAndroidBuildActions(ctx ModuleContext) { + m.distFiles = m.GenerateTaggedDistFiles(ctx) } func (m *customModule) AndroidMk() AndroidMkData { @@ -36,6 +39,26 @@ func (m *customModule) AndroidMk() AndroidMkData { } } +func (m *customModule) OutputFiles(tag string) (Paths, error) { + switch tag { + case "": + return PathsForTesting("one.out"), nil + case ".multiple": + return PathsForTesting("two.out", "three/four.out"), nil + default: + return nil, fmt.Errorf("unsupported module reference tag %q", tag) + } +} + +func (m *customModule) AndroidMkEntries() []AndroidMkEntries { + return []AndroidMkEntries{ + { + Class: "CUSTOM_MODULE", + DistFiles: m.distFiles, + }, + } +} + func customModuleFactory() Module { module := &customModule{} InitAndroidModule(module) @@ -76,3 +99,159 @@ func TestAndroidMkSingleton_PassesUpdatedAndroidMkDataToCustomCallback(t *testin assertEqual([]string{"baz"}, m.data.Host_required) assertEqual([]string{"qux"}, m.data.Target_required) } + +func TestGetDistForGoals(t *testing.T) { + testCases := []struct { + bp string + expectedAndroidMkLines []string + }{ + { + bp: ` + custom { + name: "foo", + dist: { + targets: ["my_goal"] + } + } + `, + expectedAndroidMkLines: []string{ + ".PHONY: my_goal\n", + "$(call dist-for-goals,my_goal,one.out:one.out)\n", + }, + }, + { + bp: ` + custom { + name: "foo", + dists: [ + { + targets: ["my_goal"], + }, + { + targets: ["my_second_goal", "my_third_goal"], + }, + ], + } + `, + expectedAndroidMkLines: []string{ + ".PHONY: my_goal\n", + "$(call dist-for-goals,my_goal,one.out:one.out)\n", + ".PHONY: my_second_goal my_third_goal\n", + "$(call dist-for-goals,my_second_goal my_third_goal,one.out:one.out)\n", + }, + }, + { + bp: ` + custom { + name: "foo", + dist: { + targets: ["my_goal"], + }, + dists: [ + { + targets: ["my_second_goal", "my_third_goal"], + }, + ], + } + `, + expectedAndroidMkLines: []string{ + ".PHONY: my_second_goal my_third_goal\n", + "$(call dist-for-goals,my_second_goal my_third_goal,one.out:one.out)\n", + ".PHONY: my_goal\n", + "$(call dist-for-goals,my_goal,one.out:one.out)\n", + }, + }, + { + bp: ` + custom { + name: "foo", + dist: { + targets: ["my_goal", "my_other_goal"], + tag: ".multiple", + }, + dists: [ + { + targets: ["my_second_goal"], + tag: ".multiple", + }, + { + targets: ["my_third_goal"], + dir: "test/dir", + }, + { + targets: ["my_fourth_goal"], + suffix: ".suffix", + }, + { + targets: ["my_fifth_goal"], + dest: "new-name", + }, + { + targets: ["my_sixth_goal"], + dest: "new-name", + dir: "some/dir", + suffix: ".suffix", + }, + ], + } + `, + expectedAndroidMkLines: []string{ + ".PHONY: my_second_goal\n", + "$(call dist-for-goals,my_second_goal,two.out:two.out)\n", + "$(call dist-for-goals,my_second_goal,three/four.out:four.out)\n", + ".PHONY: my_third_goal\n", + "$(call dist-for-goals,my_third_goal,one.out:test/dir/one.out)\n", + ".PHONY: my_fourth_goal\n", + "$(call dist-for-goals,my_fourth_goal,one.out:one.suffix.out)\n", + ".PHONY: my_fifth_goal\n", + "$(call dist-for-goals,my_fifth_goal,one.out:new-name)\n", + ".PHONY: my_sixth_goal\n", + "$(call dist-for-goals,my_sixth_goal,one.out:some/dir/new-name.suffix)\n", + ".PHONY: my_goal my_other_goal\n", + "$(call dist-for-goals,my_goal my_other_goal,two.out:two.out)\n", + "$(call dist-for-goals,my_goal my_other_goal,three/four.out:four.out)\n", + }, + }, + } + + for _, testCase := range testCases { + config := TestConfig(buildDir, nil, testCase.bp, nil) + config.inMake = true // Enable androidmk Singleton + + ctx := NewTestContext() + ctx.RegisterSingletonType("androidmk", AndroidMkSingleton) + ctx.RegisterModuleType("custom", customModuleFactory) + ctx.Register(config) + + _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) + FailIfErrored(t, errs) + _, errs = ctx.PrepareBuildActions(config) + FailIfErrored(t, errs) + + module := ctx.ModuleForTests("foo", "").Module().(*customModule) + entries := AndroidMkEntriesForTest(t, config, "", module) + if len(entries) != 1 { + t.Errorf("Expected a single AndroidMk entry, got %d", len(entries)) + } + androidMkLines := entries[0].GetDistForGoals(module) + + if len(androidMkLines) != len(testCase.expectedAndroidMkLines) { + t.Errorf( + "Expected %d AndroidMk lines, got %d:\n%v", + len(testCase.expectedAndroidMkLines), + len(androidMkLines), + androidMkLines, + ) + } + for idx, line := range androidMkLines { + expectedLine := testCase.expectedAndroidMkLines[idx] + if line != expectedLine { + t.Errorf( + "Expected AndroidMk line to be '%s', got '%s'", + line, + expectedLine, + ) + } + } + } +} diff --git a/android/apex.go b/android/apex.go index 30152db29..47f07ca96 100644 --- a/android/apex.go +++ b/android/apex.go @@ -124,6 +124,10 @@ type ApexModule interface { // the private part of the listed APEXes even when it is not included in the // APEXes. TestFor() []string + + // Returns nil if this module supports sdkVersion + // Otherwise, returns error with reason + ShouldSupportSdkVersion(ctx BaseModuleContext, sdkVersion int) error } type ApexProperties struct { @@ -477,3 +481,125 @@ func (d *ApexBundleDepsInfo) BuildDepsInfoLists(ctx ModuleContext, minSdkVersion }, }) } + +// TODO(b/158059172): remove minSdkVersion allowlist +var minSdkVersionAllowlist = map[string]int{ + "adbd": 30, + "android.net.ipsec.ike": 30, + "androidx-constraintlayout_constraintlayout-solver": 30, + "androidx.annotation_annotation": 28, + "androidx.arch.core_core-common": 28, + "androidx.collection_collection": 28, + "androidx.lifecycle_lifecycle-common": 28, + "apache-commons-compress": 29, + "bouncycastle_ike_digests": 30, + "brotli-java": 29, + "captiveportal-lib": 28, + "flatbuffer_headers": 30, + "framework-permission": 30, + "framework-statsd": 30, + "gemmlowp_headers": 30, + "ike-internals": 30, + "kotlinx-coroutines-android": 28, + "kotlinx-coroutines-core": 28, + "libadb_crypto": 30, + "libadb_pairing_auth": 30, + "libadb_pairing_connection": 30, + "libadb_pairing_server": 30, + "libadb_protos": 30, + "libadb_tls_connection": 30, + "libadbconnection_client": 30, + "libadbconnection_server": 30, + "libadbd_core": 30, + "libadbd_services": 30, + "libadbd": 30, + "libapp_processes_protos_lite": 30, + "libasyncio": 30, + "libbrotli": 30, + "libbuildversion": 30, + "libcrypto_static": 30, + "libcrypto_utils": 30, + "libdiagnose_usb": 30, + "libeigen": 30, + "liblz4": 30, + "libmdnssd": 30, + "libneuralnetworks_common": 30, + "libneuralnetworks_headers": 30, + "libneuralnetworks": 30, + "libprocpartition": 30, + "libprotobuf-java-lite": 30, + "libprotoutil": 30, + "libqemu_pipe": 30, + "libstats_jni": 30, + "libstatslog_statsd": 30, + "libstatsmetadata": 30, + "libstatspull": 30, + "libstatssocket": 30, + "libsync": 30, + "libtextclassifier_hash_headers": 30, + "libtextclassifier_hash_static": 30, + "libtflite_kernel_utils": 30, + "libwatchdog": 29, + "libzstd": 30, + "metrics-constants-protos": 28, + "net-utils-framework-common": 29, + "permissioncontroller-statsd": 28, + "philox_random_headers": 30, + "philox_random": 30, + "service-permission": 30, + "service-statsd": 30, + "statsd-aidl-ndk_platform": 30, + "statsd": 30, + "tensorflow_headers": 30, + "xz-java": 29, +} + +// Function called while walking an APEX's payload dependencies. +// +// Return true if the `to` module should be visited, false otherwise. +type PayloadDepsCallback func(ctx ModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool + +// UpdatableModule represents updatable APEX/APK +type UpdatableModule interface { + Module + WalkPayloadDeps(ctx ModuleContext, do PayloadDepsCallback) +} + +// CheckMinSdkVersion checks if every dependency of an updatable module sets min_sdk_version accordingly +func CheckMinSdkVersion(m UpdatableModule, ctx ModuleContext, minSdkVersion int) { + // do not enforce min_sdk_version for host + if ctx.Host() { + return + } + + // do not enforce for coverage build + if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT") || ctx.DeviceConfig().NativeCoverageEnabled() || ctx.DeviceConfig().ClangCoverageEnabled() { + return + } + + // do not enforce deps.min_sdk_version if APEX/APK doesn't set min_sdk_version or + // min_sdk_version is not finalized (e.g. current or codenames) + if minSdkVersion == FutureApiLevel { + return + } + + m.WalkPayloadDeps(ctx, func(ctx ModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool { + if externalDep { + // external deps are outside the payload boundary, which is "stable" interface. + // We don't have to check min_sdk_version for external dependencies. + return false + } + if am, ok := from.(DepIsInSameApex); ok && !am.DepIsInSameApex(ctx, to) { + return false + } + if err := to.ShouldSupportSdkVersion(ctx, minSdkVersion); err != nil { + toName := ctx.OtherModuleName(to) + if ver, ok := minSdkVersionAllowlist[toName]; !ok || ver > minSdkVersion { + ctx.OtherModuleErrorf(to, "should support min_sdk_version(%v) for %q: %v. Dependency path: %s", + minSdkVersion, ctx.ModuleName(), err.Error(), ctx.GetPathString(false)) + return false + } + } + return true + }) +} diff --git a/android/config.go b/android/config.go index 16f3d7321..6f73a12c6 100644 --- a/android/config.go +++ b/android/config.go @@ -1052,7 +1052,7 @@ func (c *deviceConfig) SamplingPGO() bool { // represents any path. func (c *deviceConfig) JavaCoverageEnabledForPath(path string) bool { coverage := false - if c.config.productVariables.JavaCoveragePaths == nil || + if len(c.config.productVariables.JavaCoveragePaths) == 0 || InList("*", c.config.productVariables.JavaCoveragePaths) || HasAnyPrefix(path, c.config.productVariables.JavaCoveragePaths) { coverage = true diff --git a/android/hooks.go b/android/hooks.go index f43a007a0..85fc08168 100644 --- a/android/hooks.go +++ b/android/hooks.go @@ -120,6 +120,7 @@ func (l *loadHookContext) registerScopedModuleType(name string, factory blueprin type InstallHookContext interface { ModuleContext + SrcPath() Path Path() InstallPath Symlink() bool } @@ -134,10 +135,17 @@ func AddInstallHook(m blueprint.Module, hook func(InstallHookContext)) { type installHookContext struct { ModuleContext + srcPath Path path InstallPath symlink bool } +var _ InstallHookContext = &installHookContext{} + +func (x *installHookContext) SrcPath() Path { + return x.srcPath +} + func (x *installHookContext) Path() InstallPath { return x.path } @@ -146,10 +154,11 @@ func (x *installHookContext) Symlink() bool { return x.symlink } -func (x *hooks) runInstallHooks(ctx ModuleContext, path InstallPath, symlink bool) { +func (x *hooks) runInstallHooks(ctx ModuleContext, srcPath Path, path InstallPath, symlink bool) { if len(x.install) > 0 { mctx := &installHookContext{ ModuleContext: ctx, + srcPath: srcPath, path: path, symlink: symlink, } diff --git a/android/module.go b/android/module.go index f24047cd5..06079cae9 100644 --- a/android/module.go +++ b/android/module.go @@ -315,6 +315,28 @@ func newPackageId(pkg string) qualifiedModuleName { return qualifiedModuleName{pkg: pkg, name: ""} } +type Dist struct { + // Copy the output of this module to the $DIST_DIR when `dist` is specified on the + // command line and any of these targets are also on the command line, or otherwise + // built + Targets []string `android:"arch_variant"` + + // The name of the output artifact. This defaults to the basename of the output of + // the module. + Dest *string `android:"arch_variant"` + + // The directory within the dist directory to store the artifact. Defaults to the + // top level directory (""). + Dir *string `android:"arch_variant"` + + // A suffix to add to the artifact file name (before any extension). + Suffix *string `android:"arch_variant"` + + // A string tag to select the OutputFiles associated with the tag. Defaults to the + // the empty "" string. + Tag *string `android:"arch_variant"` +} + type nameProperties struct { // The name of the module. Must be unique across all modules. Name *string @@ -454,23 +476,13 @@ type commonProperties struct { // relative path to a file to include in the list of notices for the device Notice *string `android:"path"` - Dist struct { - // copy the output of this module to the $DIST_DIR when `dist` is specified on the - // command line and any of these targets are also on the command line, or otherwise - // built - Targets []string `android:"arch_variant"` - - // The name of the output artifact. This defaults to the basename of the output of - // the module. - Dest *string `android:"arch_variant"` + // configuration to distribute output files from this module to the distribution + // directory (default: $OUT/dist, configurable with $DIST_DIR) + Dist Dist `android:"arch_variant"` - // The directory within the dist directory to store the artifact. Defaults to the - // top level directory (""). - Dir *string `android:"arch_variant"` - - // A suffix to add to the artifact file name (before any extension). - Suffix *string `android:"arch_variant"` - } `android:"arch_variant"` + // a list of configurations to distribute output files from this module to the + // distribution directory (default: $OUT/dist, configurable with $DIST_DIR) + Dists []Dist `android:"arch_variant"` // The OsType of artifacts that this module variant is responsible for creating. // @@ -537,6 +549,14 @@ type commonProperties struct { ImageVariation string `blueprint:"mutated"` } +// A map of OutputFile tag keys to Paths, for disting purposes. +type TaggedDistFiles map[string]Paths + +func MakeDefaultDistFiles(paths ...Path) TaggedDistFiles { + // The default OutputFile tag is the empty "" string. + return TaggedDistFiles{"": paths} +} + type hostAndDeviceProperties struct { // If set to true, build a variant of the module for the host. Defaults to false. Host_supported *bool @@ -815,6 +835,41 @@ func (m *ModuleBase) visibilityProperties() []visibilityProperty { return m.visibilityPropertyInfo } +func (m *ModuleBase) Dists() []Dist { + if len(m.commonProperties.Dist.Targets) > 0 { + // Make a copy of the underlying Dists slice to protect against + // backing array modifications with repeated calls to this method. + distsCopy := append([]Dist(nil), m.commonProperties.Dists...) + return append(distsCopy, m.commonProperties.Dist) + } else { + return m.commonProperties.Dists + } +} + +func (m *ModuleBase) GenerateTaggedDistFiles(ctx BaseModuleContext) TaggedDistFiles { + distFiles := make(TaggedDistFiles) + for _, dist := range m.Dists() { + var tag string + var distFilesForTag Paths + if dist.Tag == nil { + tag = "" + } else { + tag = *dist.Tag + } + distFilesForTag, err := m.base().module.(OutputFileProducer).OutputFiles(tag) + if err != nil { + ctx.PropertyErrorf("dist.tag", "%s", err.Error()) + } + for _, distFile := range distFilesForTag { + if distFile != nil && !distFiles[tag].containsPath(distFile) { + distFiles[tag] = append(distFiles[tag], distFile) + } + } + } + + return distFiles +} + func (m *ModuleBase) Target() Target { return m.commonProperties.CompileTarget } @@ -1959,7 +2014,7 @@ func (m *moduleContext) installFile(installPath InstallPath, name string, srcPat rule blueprint.Rule, deps []Path) InstallPath { fullInstallPath := installPath.Join(m, name) - m.module.base().hooks.runInstallHooks(m, fullInstallPath, false) + m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, false) if !m.skipInstall(fullInstallPath) { @@ -1993,7 +2048,7 @@ func (m *moduleContext) installFile(installPath InstallPath, name string, srcPat func (m *moduleContext) InstallSymlink(installPath InstallPath, name string, srcPath InstallPath) InstallPath { fullInstallPath := installPath.Join(m, name) - m.module.base().hooks.runInstallHooks(m, fullInstallPath, true) + m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, true) if !m.skipInstall(fullInstallPath) { @@ -2022,7 +2077,7 @@ func (m *moduleContext) InstallSymlink(installPath InstallPath, name string, src // (e.g. /apex/...) func (m *moduleContext) InstallAbsoluteSymlink(installPath InstallPath, name string, absPath string) InstallPath { fullInstallPath := installPath.Join(m, name) - m.module.base().hooks.runInstallHooks(m, fullInstallPath, true) + m.module.base().hooks.runInstallHooks(m, nil, fullInstallPath, true) if !m.skipInstall(fullInstallPath) { m.Build(pctx, BuildParams{ diff --git a/android/override_module.go b/android/override_module.go index 7e58890d7..6b246db41 100644 --- a/android/override_module.go +++ b/android/override_module.go @@ -42,6 +42,11 @@ type OverrideModule interface { setOverridingProperties(properties []interface{}) getOverrideModuleProperties() *OverrideModuleProperties + + // Internal funcs to handle interoperability between override modules and prebuilts. + // i.e. cases where an overriding module, too, is overridden by a prebuilt module. + setOverriddenByPrebuilt(overridden bool) + getOverriddenByPrebuilt() bool } // Base module struct for override module types @@ -49,6 +54,8 @@ type OverrideModuleBase struct { moduleProperties OverrideModuleProperties overridingProperties []interface{} + + overriddenByPrebuilt bool } type OverrideModuleProperties struct { @@ -74,6 +81,14 @@ func (o *OverrideModuleBase) GetOverriddenModuleName() string { return proptools.String(o.moduleProperties.Base) } +func (o *OverrideModuleBase) setOverriddenByPrebuilt(overridden bool) { + o.overriddenByPrebuilt = overridden +} + +func (o *OverrideModuleBase) getOverriddenByPrebuilt() bool { + return o.overriddenByPrebuilt +} + func InitOverrideModule(m OverrideModule) { m.setOverridingProperties(m.GetProperties()) @@ -208,21 +223,24 @@ var overrideBaseDepTag overrideBaseDependencyTag // next phase. func overrideModuleDepsMutator(ctx BottomUpMutatorContext) { if module, ok := ctx.Module().(OverrideModule); ok { - // Skip this overriding module if there's a prebuilt module that overrides it with prefer flag. - overriddenByPrebuilt := false + base := String(module.getOverrideModuleProperties().Base) + if !ctx.OtherModuleExists(base) { + ctx.PropertyErrorf("base", "%q is not a valid module name", base) + return + } + // See if there's a prebuilt module that overrides this override module with prefer flag, + // in which case we call SkipInstall on the corresponding variant later. ctx.VisitDirectDepsWithTag(PrebuiltDepTag, func(dep Module) { prebuilt, ok := dep.(PrebuiltInterface) if !ok { panic("PrebuiltDepTag leads to a non-prebuilt module " + dep.Name()) } if prebuilt.Prebuilt().UsePrebuilt() { - overriddenByPrebuilt = true + module.setOverriddenByPrebuilt(true) return } }) - if !overriddenByPrebuilt { - ctx.AddDependency(ctx.Module(), overrideBaseDepTag, *module.getOverrideModuleProperties().Base) - } + ctx.AddDependency(ctx.Module(), overrideBaseDepTag, *module.getOverrideModuleProperties().Base) } } @@ -258,6 +276,10 @@ func performOverrideMutator(ctx BottomUpMutatorContext) { ctx.AliasVariation(variants[0]) for i, o := range overrides { mods[i+1].(OverridableModule).override(ctx, o) + if o.getOverriddenByPrebuilt() { + // The overriding module itself, too, is overridden by a prebuilt. Skip its installation. + mods[i+1].SkipInstall() + } } } else if o, ok := ctx.Module().(OverrideModule); ok { // Create a variant of the overriding module with its own name. This matches the above local diff --git a/android/paths.go b/android/paths.go index bed6f3f58..d8d51a777 100644 --- a/android/paths.go +++ b/android/paths.go @@ -220,6 +220,15 @@ func (p OptionalPath) String() string { // Paths is a slice of Path objects, with helpers to operate on the collection. type Paths []Path +func (paths Paths) containsPath(path Path) bool { + for _, p := range paths { + if p == path { + return true + } + } + return false +} + // PathsForSource returns Paths rooted from SrcDir func PathsForSource(ctx PathContext, paths []string) Paths { ret := make(Paths, len(paths)) diff --git a/androidmk/androidmk/androidmk.go b/androidmk/androidmk/androidmk.go index dcd67d871..03cf74d83 100644 --- a/androidmk/androidmk/androidmk.go +++ b/androidmk/androidmk/androidmk.go @@ -458,6 +458,9 @@ func setVariable(file *bpFile, plusequals bool, prefix, name string, value bppar } file.defs = append(file.defs, a) } else { + if _, ok := file.globalAssignments[name]; ok { + return fmt.Errorf("cannot assign a variable multiple times: \"%s\"", name) + } a := &bpparser.Assignment{ Name: name, NamePos: pos, diff --git a/androidmk/androidmk/androidmk_test.go b/androidmk/androidmk/androidmk_test.go index 4f307c4fb..726746bdd 100644 --- a/androidmk/androidmk/androidmk_test.go +++ b/androidmk/androidmk/androidmk_test.go @@ -1389,6 +1389,35 @@ cc_binary { `, }, { + desc: "variableReassigned", + in: ` +include $(CLEAR_VARS) + +src_files:= a.cpp + +LOCAL_SRC_FILES:= $(src_files) +LOCAL_MODULE:= test +include $(BUILD_EXECUTABLE) + +# clear locally used variable +src_files:= +`, + expected: ` + + +src_files = ["a.cpp"] +cc_binary { + name: "test", + + srcs: src_files, +} + +// clear locally used variable +// ANDROIDMK TRANSLATION ERROR: cannot assign a variable multiple times: "src_files" +// src_files := +`, + }, + { desc: "undefined_boolean_var", in: ` include $(CLEAR_VARS) diff --git a/apex/apex.go b/apex/apex.go index 58cbb13e9..a9be1a8ae 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -16,7 +16,6 @@ package apex import ( "fmt" - "path" "path/filepath" "sort" "strings" @@ -1242,7 +1241,7 @@ type apexBundle struct { container_certificate_file android.Path container_private_key_file android.Path - fileContexts android.Path + fileContexts android.WritablePath // list of files to be included in this apex filesInfo []apexFile @@ -1724,13 +1723,8 @@ func (c *flattenedApexContext) InstallBypassMake() bool { return true } -// Function called while walking an APEX's payload dependencies. -// -// Return true if the `to` module should be visited, false otherwise. -type payloadDepsCallback func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool - // Visit dependencies that contributes to the payload of this APEX -func (a *apexBundle) walkPayloadDeps(ctx android.ModuleContext, do payloadDepsCallback) { +func (a *apexBundle) WalkPayloadDeps(ctx android.ModuleContext, do android.PayloadDepsCallback) { ctx.WalkDeps(func(child, parent android.Module) bool { am, ok := child.(android.ApexModule) if !ok || !am.CanHaveApexVariants() { @@ -1756,7 +1750,21 @@ func (a *apexBundle) walkPayloadDeps(ctx android.ModuleContext, do payloadDepsCa } func (a *apexBundle) minSdkVersion(ctx android.BaseModuleContext) int { - ver := proptools.StringDefault(a.properties.Min_sdk_version, "current") + ver := proptools.String(a.properties.Min_sdk_version) + if ver == "" { + return android.FutureApiLevel + } + // Treat the current codenames as "current", which means future API version (10000) + // Otherwise, ApiStrToNum converts codename(non-finalized) to a value from [9000...] + // and would fail to build against "current". + if android.InList(ver, ctx.Config().PlatformVersionActiveCodenames()) { + return android.FutureApiLevel + } + // In "REL" branch, "current" is mapped to finalized sdk version + if ctx.Config().PlatformSdkCodename() == "REL" && ver == "current" { + return ctx.Config().PlatformSdkVersionInt() + } + // Finalized codenames are OKAY and will be converted to int intVer, err := android.ApiStrToNum(ctx, ver) if err != nil { ctx.PropertyErrorf("min_sdk_version", "%s", err.Error()) @@ -1784,7 +1792,7 @@ func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) { return } - a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool { + a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool { if externalDep { // As soon as the dependency graph crosses the APEX boundary, don't go further. return false @@ -1820,6 +1828,17 @@ func (a *apexBundle) checkUpdatable(ctx android.ModuleContext) { } } +func (a *apexBundle) checkMinSdkVersion(ctx android.ModuleContext) { + if a.testApex || a.vndkApex { + return + } + // Meaningless to check min_sdk_version when building use_vendor modules against non-Trebleized targets + if proptools.Bool(a.properties.Use_vendor) && ctx.DeviceConfig().VndkVersion() == "" { + return + } + android.CheckMinSdkVersion(a, ctx, a.minSdkVersion(ctx)) +} + // Ensures that a lib providing stub isn't statically linked func (a *apexBundle) checkStaticLinkingToStubLibraries(ctx android.ModuleContext) { // Practically, we only care about regular APEXes on the device. @@ -1827,7 +1846,7 @@ func (a *apexBundle) checkStaticLinkingToStubLibraries(ctx android.ModuleContext return } - a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool { + a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool { if ccm, ok := to.(*cc.Module); ok { apexName := ctx.ModuleName() fromName := ctx.OtherModuleName(from) @@ -1866,7 +1885,7 @@ func (a *apexBundle) checkStaticLinkingToStubLibraries(ctx android.ModuleContext } func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { - buildFlattenedAsDefault := ctx.Config().FlattenApex() && !ctx.Config().UnbundledBuild() + buildFlattenedAsDefault := ctx.Config().FlattenApex() && !ctx.Config().UnbundledBuildApps() switch a.properties.ApexType { case imageApex: if buildFlattenedAsDefault { @@ -1902,6 +1921,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.checkApexAvailability(ctx) a.checkUpdatable(ctx) + a.checkMinSdkVersion(ctx) a.checkStaticLinkingToStubLibraries(ctx) handleSpecialLibs := !android.Bool(a.properties.Ignore_system_library_special_case) @@ -1935,7 +1955,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { }) var filesInfo []apexFile - // TODO(jiyong) do this using walkPayloadDeps + // TODO(jiyong) do this using WalkPayloadDeps ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool { depTag := ctx.OtherModuleDependencyTag(child) if _, ok := depTag.(android.ExcludeFromApexContentsTag); ok { @@ -2174,22 +2194,6 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.installDir = android.PathForModuleInstall(ctx, "apex") a.filesInfo = filesInfo - if a.properties.ApexType != zipApex { - if a.properties.File_contexts == nil { - a.fileContexts = android.PathForSource(ctx, "system/sepolicy/apex", ctx.ModuleName()+"-file_contexts") - } else { - a.fileContexts = android.PathForModuleSrc(ctx, *a.properties.File_contexts) - if a.Platform() { - if matched, err := path.Match("system/sepolicy/**/*", a.fileContexts.String()); err != nil || !matched { - ctx.PropertyErrorf("file_contexts", "should be under system/sepolicy, but %q", a.fileContexts) - } - } - } - if !android.ExistentPathForSource(ctx, a.fileContexts.String()).Valid() { - ctx.PropertyErrorf("file_contexts", "cannot find file_contexts file: %q", a.fileContexts) - return - } - } // 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 @@ -2213,6 +2217,8 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { // prepare apex_manifest.json a.buildManifest(ctx, provideNativeLibs, requireNativeLibs) + a.buildFileContexts(ctx) + a.setCertificateAndPrivateKey(ctx) if a.properties.ApexType == flattenedApex { a.buildFlattenedApex(ctx) diff --git a/apex/apex_test.go b/apex/apex_test.go index 3d5886ea9..f1638c3bc 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -206,6 +206,7 @@ func testApexContext(_ *testing.T, bp string, handlers ...testCustomizer) (*andr config.TestProductVariables.CertificateOverrides = []string{"myapex_keytest:myapex.certificate.override"} config.TestProductVariables.Platform_sdk_codename = proptools.StringPtr("Q") config.TestProductVariables.Platform_sdk_final = proptools.BoolPtr(false) + config.TestProductVariables.Platform_version_active_codenames = []string{"R"} config.TestProductVariables.Platform_vndk_version = proptools.StringPtr("VER") for _, handler := range handlers { @@ -1104,13 +1105,13 @@ func TestApexDependsOnLLNDKTransitively(t *testing.T) { }{ { name: "should link to the latest", - minSdkVersion: "current", + minSdkVersion: "", shouldLink: "30", shouldNotLink: []string{"29"}, }, { name: "should link to llndk#29", - minSdkVersion: "29", + minSdkVersion: "min_sdk_version: \"29\",", shouldLink: "29", shouldNotLink: []string{"30"}, }, @@ -1123,7 +1124,7 @@ func TestApexDependsOnLLNDKTransitively(t *testing.T) { key: "myapex.key", use_vendor: true, native_shared_libs: ["mylib"], - min_sdk_version: "`+tc.minSdkVersion+`", + `+tc.minSdkVersion+` } apex_key { @@ -1140,6 +1141,7 @@ func TestApexDependsOnLLNDKTransitively(t *testing.T) { system_shared_libs: [], stl: "none", apex_available: [ "myapex" ], + min_sdk_version: "29", } cc_library { @@ -1270,24 +1272,24 @@ func TestApexWithSystemLibsStubs(t *testing.T) { ensureContains(t, libFlags, "libdl/android_arm64_armv8-a_shared/libdl.so") } -func TestApexUseStubsAccordingToMinSdkVersionInUnbundledBuild(t *testing.T) { +func TestApexMinSdkVersion_NativeModulesShouldBeBuiltAgainstStubs(t *testing.T) { // there are three links between liba --> libz - // 1) myapex -> libx -> liba -> libz : this should be #2 link, but fallback to #1 - // 2) otherapex -> liby -> liba -> libz : this should be #3 link + // 1) myapex -> libx -> liba -> libz : this should be #29 link, but fallback to #28 + // 2) otherapex -> liby -> liba -> libz : this should be #30 link // 3) (platform) -> liba -> libz : this should be non-stub link ctx, _ := testApex(t, ` apex { name: "myapex", key: "myapex.key", native_shared_libs: ["libx"], - min_sdk_version: "2", + min_sdk_version: "29", } apex { name: "otherapex", key: "myapex.key", native_shared_libs: ["liby"], - min_sdk_version: "3", + min_sdk_version: "30", } apex_key { @@ -1302,6 +1304,7 @@ func TestApexUseStubsAccordingToMinSdkVersionInUnbundledBuild(t *testing.T) { system_shared_libs: [], stl: "none", apex_available: [ "myapex" ], + min_sdk_version: "29", } cc_library { @@ -1310,6 +1313,7 @@ func TestApexUseStubsAccordingToMinSdkVersionInUnbundledBuild(t *testing.T) { system_shared_libs: [], stl: "none", apex_available: [ "otherapex" ], + min_sdk_version: "29", } cc_library { @@ -1321,6 +1325,7 @@ func TestApexUseStubsAccordingToMinSdkVersionInUnbundledBuild(t *testing.T) { "//apex_available:anyapex", "//apex_available:platform", ], + min_sdk_version: "29", } cc_library { @@ -1328,10 +1333,10 @@ func TestApexUseStubsAccordingToMinSdkVersionInUnbundledBuild(t *testing.T) { system_shared_libs: [], stl: "none", stubs: { - versions: ["1", "3"], + versions: ["28", "30"], }, } - `, withUnbundledBuild) + `) expectLink := func(from, from_variant, to, to_variant string) { ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"] @@ -1343,13 +1348,13 @@ func TestApexUseStubsAccordingToMinSdkVersionInUnbundledBuild(t *testing.T) { } // platform liba is linked to non-stub version expectLink("liba", "shared", "libz", "shared") - // liba in myapex is linked to #1 - expectLink("liba", "shared_myapex", "libz", "shared_1") - expectNoLink("liba", "shared_myapex", "libz", "shared_3") + // liba in myapex is linked to #28 + expectLink("liba", "shared_myapex", "libz", "shared_28") + expectNoLink("liba", "shared_myapex", "libz", "shared_30") expectNoLink("liba", "shared_myapex", "libz", "shared") - // liba in otherapex is linked to #3 - expectLink("liba", "shared_otherapex", "libz", "shared_3") - expectNoLink("liba", "shared_otherapex", "libz", "shared_1") + // liba in otherapex is linked to #30 + expectLink("liba", "shared_otherapex", "libz", "shared_30") + expectNoLink("liba", "shared_otherapex", "libz", "shared_28") expectNoLink("liba", "shared_otherapex", "libz", "shared") } @@ -1374,6 +1379,7 @@ func TestApexMinSdkVersion_SupportsCodeNames(t *testing.T) { system_shared_libs: [], stl: "none", apex_available: [ "myapex" ], + min_sdk_version: "R", } cc_library { @@ -1407,7 +1413,7 @@ func TestApexMinSdkVersion_SupportsCodeNames(t *testing.T) { expectNoLink("libx", "shared_myapex", "libz", "shared") } -func TestApexMinSdkVersionDefaultsToLatest(t *testing.T) { +func TestApexMinSdkVersion_DefaultsToLatest(t *testing.T) { ctx, _ := testApex(t, ` apex { name: "myapex", @@ -1516,6 +1522,7 @@ func TestQApexesUseLatestStubsInBundledBuildsAndHWASAN(t *testing.T) { name: "libx", shared_libs: ["libbar"], apex_available: [ "myapex" ], + min_sdk_version: "29", } cc_library { @@ -1553,6 +1560,7 @@ func TestQTargetApexUsesStaticUnwinder(t *testing.T) { cc_library { name: "libx", apex_available: [ "myapex" ], + min_sdk_version: "29", } `) @@ -1564,7 +1572,7 @@ func TestQTargetApexUsesStaticUnwinder(t *testing.T) { ensureListNotContains(t, cm.Properties.AndroidMkStaticLibs, "libgcc_stripped") } -func TestInvalidMinSdkVersion(t *testing.T) { +func TestApexMinSdkVersion_ErrorIfIncompatibleStubs(t *testing.T) { testApexError(t, `"libz" .*: not found a version\(<=29\)`, ` apex { name: "myapex", @@ -1585,6 +1593,7 @@ func TestInvalidMinSdkVersion(t *testing.T) { system_shared_libs: [], stl: "none", apex_available: [ "myapex" ], + min_sdk_version: "29", } cc_library { @@ -1596,12 +1605,15 @@ func TestInvalidMinSdkVersion(t *testing.T) { }, } `) +} - testApexError(t, `"myapex" .*: min_sdk_version: SDK version should be .*`, ` +func TestApexMinSdkVersion_ErrorIfIncompatibleVersion(t *testing.T) { + testApexError(t, `module "mylib".*: should support min_sdk_version\(29\)`, ` apex { name: "myapex", key: "myapex.key", - min_sdk_version: "abc", + native_shared_libs: ["mylib"], + min_sdk_version: "29", } apex_key { @@ -1609,6 +1621,67 @@ func TestInvalidMinSdkVersion(t *testing.T) { public_key: "testkey.avbpubkey", private_key: "testkey.pem", } + + cc_library { + name: "mylib", + srcs: ["mylib.cpp"], + system_shared_libs: [], + stl: "none", + apex_available: [ + "myapex", + ], + min_sdk_version: "30", + } + `) +} + +func TestApexMinSdkVersion_Okay(t *testing.T) { + testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + native_shared_libs: ["libfoo"], + java_libs: ["libbar"], + min_sdk_version: "29", + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + cc_library { + name: "libfoo", + srcs: ["mylib.cpp"], + shared_libs: ["libfoo_dep"], + apex_available: ["myapex"], + min_sdk_version: "29", + } + + cc_library { + name: "libfoo_dep", + srcs: ["mylib.cpp"], + apex_available: ["myapex"], + min_sdk_version: "29", + } + + java_library { + name: "libbar", + sdk_version: "current", + srcs: ["a.java"], + static_libs: ["libbar_dep"], + apex_available: ["myapex"], + min_sdk_version: "29", + } + + java_library { + name: "libbar_dep", + sdk_version: "current", + srcs: ["a.java"], + apex_available: ["myapex"], + min_sdk_version: "29", + } `) } @@ -1659,6 +1732,7 @@ func TestJavaStableSdkVersion(t *testing.T) { srcs: ["foo/bar/MyClass.java"], sdk_version: "current", apex_available: ["myapex"], + min_sdk_version: "29", } `, }, @@ -1728,6 +1802,135 @@ func TestJavaStableSdkVersion(t *testing.T) { } } +func TestApexMinSdkVersion_ErrorIfDepIsNewer(t *testing.T) { + testApexError(t, `module "mylib2".*: should support min_sdk_version\(29\) for "myapex"`, ` + apex { + name: "myapex", + key: "myapex.key", + native_shared_libs: ["mylib"], + min_sdk_version: "29", + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + cc_library { + name: "mylib", + srcs: ["mylib.cpp"], + shared_libs: ["mylib2"], + system_shared_libs: [], + stl: "none", + apex_available: [ + "myapex", + ], + min_sdk_version: "29", + } + + // indirect part of the apex + cc_library { + name: "mylib2", + srcs: ["mylib.cpp"], + system_shared_libs: [], + stl: "none", + apex_available: [ + "myapex", + ], + min_sdk_version: "30", + } + `) +} + +func TestApexMinSdkVersion_ErrorIfDepIsNewer_Java(t *testing.T) { + testApexError(t, `module "bar".*: should support min_sdk_version\(29\) for "myapex"`, ` + apex { + name: "myapex", + key: "myapex.key", + apps: ["AppFoo"], + min_sdk_version: "29", + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + android_app { + name: "AppFoo", + srcs: ["foo/bar/MyClass.java"], + sdk_version: "current", + min_sdk_version: "29", + system_modules: "none", + stl: "none", + static_libs: ["bar"], + apex_available: [ "myapex" ], + } + + java_library { + name: "bar", + sdk_version: "current", + srcs: ["a.java"], + apex_available: [ "myapex" ], + } + `) +} + +func TestApexMinSdkVersion_OkayEvenWhenDepIsNewer_IfItSatisfiesApexMinSdkVersion(t *testing.T) { + ctx, _ := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + native_shared_libs: ["mylib"], + min_sdk_version: "29", + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + // mylib in myapex will link to mylib2#29 + // mylib in otherapex will link to mylib2(non-stub) in otherapex as well + cc_library { + name: "mylib", + srcs: ["mylib.cpp"], + shared_libs: ["mylib2"], + system_shared_libs: [], + stl: "none", + apex_available: ["myapex", "otherapex"], + min_sdk_version: "29", + } + + cc_library { + name: "mylib2", + srcs: ["mylib.cpp"], + system_shared_libs: [], + stl: "none", + apex_available: ["otherapex"], + stubs: { versions: ["29", "30"] }, + min_sdk_version: "30", + } + + apex { + name: "otherapex", + key: "myapex.key", + native_shared_libs: ["mylib", "mylib2"], + min_sdk_version: "30", + } + `) + expectLink := func(from, from_variant, to, to_variant string) { + ld := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld") + libFlags := ld.Args["libFlags"] + ensureContains(t, libFlags, "android_arm64_armv8-a_"+to_variant+"/"+to+".so") + } + expectLink("mylib", "shared_myapex", "mylib2", "shared_29") + expectLink("mylib", "shared_otherapex", "mylib2", "shared_otherapex") +} + func TestFilesInSubDir(t *testing.T) { ctx, _ := testApex(t, ` apex { @@ -2217,6 +2420,7 @@ func TestMacro(t *testing.T) { "otherapex", ], recovery_available: true, + min_sdk_version: "29", } cc_library { name: "mylib2", @@ -2228,6 +2432,7 @@ func TestMacro(t *testing.T) { "otherapex", ], use_apex_name_macro: true, + min_sdk_version: "29", } `) @@ -3275,110 +3480,104 @@ func TestApexInVariousPartition(t *testing.T) { } } -func TestFileContexts(t *testing.T) { +func TestFileContexts_FindInDefaultLocationIfNotSet(t *testing.T) { ctx, _ := testApex(t, ` - apex { - name: "myapex", - key: "myapex.key", - } + apex { + name: "myapex", + key: "myapex.key", + } - apex_key { - name: "myapex.key", - public_key: "testkey.avbpubkey", - private_key: "testkey.pem", - } + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } `) module := ctx.ModuleForTests("myapex", "android_common_myapex_image") - apexRule := module.Rule("apexRule") - actual := apexRule.Args["file_contexts"] - expected := "system/sepolicy/apex/myapex-file_contexts" - if actual != expected { - t.Errorf("wrong file_contexts. expected %q. actual %q", expected, actual) - } + rule := module.Output("file_contexts") + ensureContains(t, rule.RuleParams.Command, "cat system/sepolicy/apex/myapex-file_contexts") +} +func TestFileContexts_ShouldBeUnderSystemSepolicyForSystemApexes(t *testing.T) { testApexError(t, `"myapex" .*: file_contexts: should be under system/sepolicy`, ` - apex { - name: "myapex", - key: "myapex.key", - file_contexts: "my_own_file_contexts", - } + apex { + name: "myapex", + key: "myapex.key", + file_contexts: "my_own_file_contexts", + } - apex_key { - name: "myapex.key", - public_key: "testkey.avbpubkey", - private_key: "testkey.pem", - } + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } `, withFiles(map[string][]byte{ "my_own_file_contexts": nil, })) +} +func TestFileContexts_ProductSpecificApexes(t *testing.T) { testApexError(t, `"myapex" .*: file_contexts: cannot find`, ` - apex { - name: "myapex", - key: "myapex.key", - product_specific: true, - file_contexts: "product_specific_file_contexts", - } + apex { + name: "myapex", + key: "myapex.key", + product_specific: true, + file_contexts: "product_specific_file_contexts", + } - apex_key { - name: "myapex.key", - public_key: "testkey.avbpubkey", - private_key: "testkey.pem", - } + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } `) - ctx, _ = testApex(t, ` - apex { - name: "myapex", - key: "myapex.key", - product_specific: true, - file_contexts: "product_specific_file_contexts", - } + ctx, _ := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + product_specific: true, + file_contexts: "product_specific_file_contexts", + } - apex_key { - name: "myapex.key", - public_key: "testkey.avbpubkey", - private_key: "testkey.pem", - } + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } `, withFiles(map[string][]byte{ "product_specific_file_contexts": nil, })) - module = ctx.ModuleForTests("myapex", "android_common_myapex_image") - apexRule = module.Rule("apexRule") - actual = apexRule.Args["file_contexts"] - expected = "product_specific_file_contexts" - if actual != expected { - t.Errorf("wrong file_contexts. expected %q. actual %q", expected, actual) - } + module := ctx.ModuleForTests("myapex", "android_common_myapex_image") + rule := module.Output("file_contexts") + ensureContains(t, rule.RuleParams.Command, "cat product_specific_file_contexts") +} - ctx, _ = testApex(t, ` - apex { - name: "myapex", - key: "myapex.key", - product_specific: true, - file_contexts: ":my-file-contexts", - } +func TestFileContexts_SetViaFileGroup(t *testing.T) { + ctx, _ := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + product_specific: true, + file_contexts: ":my-file-contexts", + } - apex_key { - name: "myapex.key", - public_key: "testkey.avbpubkey", - private_key: "testkey.pem", - } + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } - filegroup { - name: "my-file-contexts", - srcs: ["product_specific_file_contexts"], - } + filegroup { + name: "my-file-contexts", + srcs: ["product_specific_file_contexts"], + } `, withFiles(map[string][]byte{ "product_specific_file_contexts": nil, })) - module = ctx.ModuleForTests("myapex", "android_common_myapex_image") - apexRule = module.Rule("apexRule") - actual = apexRule.Args["file_contexts"] - expected = "product_specific_file_contexts" - if actual != expected { - t.Errorf("wrong file_contexts. expected %q. actual %q", expected, actual) - } + module := ctx.ModuleForTests("myapex", "android_common_myapex_image") + rule := module.Output("file_contexts") + ensureContains(t, rule.RuleParams.Command, "cat product_specific_file_contexts") } func TestApexKeyFromOtherModule(t *testing.T) { @@ -4349,6 +4548,7 @@ func TestLegacyAndroid10Support(t *testing.T) { stl: "libc++", system_shared_libs: [], apex_available: [ "myapex" ], + min_sdk_version: "29", } `, withUnbundledBuild) @@ -4749,6 +4949,7 @@ func TestSymlinksFromApexToSystem(t *testing.T) { "myapex.updatable", "//apex_available:platform", ], + min_sdk_version: "current", } cc_library { @@ -4761,6 +4962,7 @@ func TestSymlinksFromApexToSystem(t *testing.T) { "myapex.updatable", "//apex_available:platform", ], + min_sdk_version: "current", } java_library { @@ -4774,6 +4976,7 @@ func TestSymlinksFromApexToSystem(t *testing.T) { "myapex.updatable", "//apex_available:platform", ], + min_sdk_version: "current", } java_library { @@ -4786,6 +4989,7 @@ func TestSymlinksFromApexToSystem(t *testing.T) { "myapex.updatable", "//apex_available:platform", ], + min_sdk_version: "current", } ` @@ -5393,7 +5597,7 @@ func TestApexKeysTxt(t *testing.T) { apexKeysText := ctx.SingletonForTests("apex_keys_text") content := apexKeysText.MaybeDescription("apexkeys.txt").BuildParams.Args["content"] ensureContains(t, content, `name="myapex_set.apex" public_key="PRESIGNED" private_key="PRESIGNED" container_certificate="PRESIGNED" container_private_key="PRESIGNED" partition="system"`) - ensureNotContains(t, content, "myapex.apex") + ensureContains(t, content, `name="myapex.apex" public_key="PRESIGNED" private_key="PRESIGNED" container_certificate="PRESIGNED" container_private_key="PRESIGNED" partition="system"`) } func TestAllowedFiles(t *testing.T) { diff --git a/apex/builder.go b/apex/builder.go index af43417aa..ede11d05e 100644 --- a/apex/builder.go +++ b/apex/builder.go @@ -17,6 +17,7 @@ package apex import ( "encoding/json" "fmt" + "path" "path/filepath" "runtime" "sort" @@ -231,10 +232,42 @@ func (a *apexBundle) buildManifest(ctx android.ModuleContext, provideNativeLibs, }) } +func (a *apexBundle) buildFileContexts(ctx android.ModuleContext) { + if a.properties.ApexType == zipApex { + return + } + var fileContexts android.Path + if a.properties.File_contexts == nil { + fileContexts = android.PathForSource(ctx, "system/sepolicy/apex", ctx.ModuleName()+"-file_contexts") + } else { + fileContexts = android.PathForModuleSrc(ctx, *a.properties.File_contexts) + } + if a.Platform() { + if matched, err := path.Match("system/sepolicy/**/*", fileContexts.String()); err != nil || !matched { + ctx.PropertyErrorf("file_contexts", "should be under system/sepolicy, but %q", fileContexts) + return + } + } + if !android.ExistentPathForSource(ctx, fileContexts.String()).Valid() { + ctx.PropertyErrorf("file_contexts", "cannot find file_contexts file: %q", a.fileContexts) + return + } + + output := android.PathForModuleOut(ctx, "file_contexts") + rule := android.NewRuleBuilder() + rule.Command().Text("rm").FlagWithOutput("-f ", output) + rule.Command().Text("cat").Input(fileContexts).Text(">>").Output(output) + rule.Command().Text("echo").Text(">>").Output(output) + rule.Command().Text("echo").Flag("/apex_manifest\\\\.pb u:object_r:system_file:s0").Text(">>").Output(output) + rule.Build(pctx, ctx, "file_contexts."+a.Name(), "Generate file_contexts") + + a.fileContexts = output.OutputPath +} + func (a *apexBundle) buildNoticeFiles(ctx android.ModuleContext, apexFileName string) android.NoticeOutputs { var noticeFiles android.Paths - a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool { + a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool { if externalDep { // As soon as the dependency graph crosses the APEX boundary, don't go further. return false @@ -733,7 +766,7 @@ func (a *apexBundle) buildApexDependencyInfo(ctx android.ModuleContext) { } depInfos := android.DepNameToDepInfoMap{} - a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool { + a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool { if from.Name() == to.Name() { // This can happen for cc.reuseObjTag. We are not interested in tracking this. // As soon as the dependency graph crosses the APEX boundary, don't go further. diff --git a/apex/key.go b/apex/key.go index a68f6e1a1..d2d5786b3 100644 --- a/apex/key.go +++ b/apex/key.go @@ -160,12 +160,6 @@ func (s *apexKeysText) GenerateBuildActions(ctx android.SingletonContext) { presigned: true, partition: m.PartitionTag(ctx.DeviceConfig()), } - - for _, om := range m.Overrides() { - if _, ok := apexKeyMap[om]; ok { - delete(apexKeyMap, om) - } - } apexKeyMap[m.BaseModuleName()] = entry } }) diff --git a/cc/androidmk.go b/cc/androidmk.go index b3ad610d6..3f812c2c0 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -249,7 +249,10 @@ func (library *libraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries entries.Class = "HEADER_LIBRARIES" } - entries.DistFile = library.distFile + if library.distFile != nil { + entries.DistFiles = android.MakeDefaultDistFiles(library.distFile) + } + entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) { library.androidMkWriteExportedFlags(entries) library.androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries) @@ -318,7 +321,7 @@ func (binary *binaryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *a ctx.subAndroidMk(entries, binary.baseInstaller) entries.Class = "EXECUTABLES" - entries.DistFile = binary.distFile + entries.DistFiles = binary.distFiles entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) { entries.SetString("LOCAL_SOONG_UNSTRIPPED_BINARY", binary.unstrippedOutputFile.String()) if len(binary.symlinks) > 0 { diff --git a/cc/binary.go b/cc/binary.go index 251b7f0c4..565cb8ae7 100644 --- a/cc/binary.go +++ b/cc/binary.go @@ -98,8 +98,8 @@ type binaryDecorator struct { // Output archive of gcno coverage information coverageOutputFile android.OptionalPath - // Location of the file that should be copied to dist dir when requested - distFile android.OptionalPath + // Location of the files that should be copied to dist dir when requested + distFiles android.TaggedDistFiles post_install_cmds []string } @@ -367,11 +367,11 @@ func (binary *binaryDecorator) link(ctx ModuleContext, binary.injectVersionSymbol(ctx, outputFile, versionedOutputFile) } else { versionedOutputFile := android.PathForModuleOut(ctx, "versioned", fileName) - binary.distFile = android.OptionalPathForPath(versionedOutputFile) + binary.distFiles = android.MakeDefaultDistFiles(versionedOutputFile) if binary.stripper.needsStrip(ctx) { out := android.PathForModuleOut(ctx, "versioned-stripped", fileName) - binary.distFile = android.OptionalPathForPath(out) + binary.distFiles = android.MakeDefaultDistFiles(out) binary.stripper.stripExecutableOrSharedLib(ctx, versionedOutputFile, out, builderFlags) } @@ -2905,6 +2905,54 @@ func (c *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Modu return true } +// b/154667674: refactor this to handle "current" in a consistent way +func decodeSdkVersionString(ctx android.BaseModuleContext, versionString string) (int, error) { + if versionString == "" { + return 0, fmt.Errorf("not specified") + } + if versionString == "current" { + if ctx.Config().PlatformSdkCodename() == "REL" { + return ctx.Config().PlatformSdkVersionInt(), nil + } + return android.FutureApiLevel, nil + } + return android.ApiStrToNum(ctx, versionString) +} + +func (c *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error { + // We ignore libclang_rt.* prebuilt libs since they declare sdk_version: 14(b/121358700) + if strings.HasPrefix(ctx.OtherModuleName(c), "libclang_rt") { + return nil + } + // b/154569636: set min_sdk_version correctly for toolchain_libraries + if c.ToolchainLibrary() { + return nil + } + // We don't check for prebuilt modules + if _, ok := c.linker.(prebuiltLinkerInterface); ok { + return nil + } + minSdkVersion := c.MinSdkVersion() + if minSdkVersion == "apex_inherit" { + return nil + } + if minSdkVersion == "" { + // JNI libs within APK-in-APEX fall into here + // Those are okay to set sdk_version instead + // We don't have to check if this is a SDK variant because + // non-SDK variant resets sdk_version, which works too. + minSdkVersion = c.SdkVersion() + } + ver, err := decodeSdkVersionString(ctx, minSdkVersion) + if err != nil { + return err + } + if ver > sdkVersion { + return fmt.Errorf("newer SDK(%v)", ver) + } + return nil +} + // // Defaults // diff --git a/cc/library.go b/cc/library.go index 968702e59..98f4d48d6 100644 --- a/cc/library.go +++ b/cc/library.go @@ -369,7 +369,7 @@ type libraryDecorator struct { unstrippedOutputFile android.Path // Location of the file that should be copied to dist dir when requested - distFile android.OptionalPath + distFile android.Path versionScriptPath android.ModuleGenPath @@ -894,7 +894,7 @@ func (library *libraryDecorator) linkStatic(ctx ModuleContext, library.injectVersionSymbol(ctx, outputFile, versionedOutputFile) } else { versionedOutputFile := android.PathForModuleOut(ctx, "versioned", fileName) - library.distFile = android.OptionalPathForPath(versionedOutputFile) + library.distFile = versionedOutputFile library.injectVersionSymbol(ctx, outputFile, versionedOutputFile) } } @@ -988,11 +988,11 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext, library.injectVersionSymbol(ctx, outputFile, versionedOutputFile) } else { versionedOutputFile := android.PathForModuleOut(ctx, "versioned", fileName) - library.distFile = android.OptionalPathForPath(versionedOutputFile) + library.distFile = versionedOutputFile if library.stripper.needsStrip(ctx) { out := android.PathForModuleOut(ctx, "versioned-stripped", fileName) - library.distFile = android.OptionalPathForPath(out) + library.distFile = out library.stripper.stripExecutableOrSharedLib(ctx, versionedOutputFile, out, builderFlags) } diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go index 441030251..9c543990f 100644 --- a/cc/library_sdk_member.go +++ b/cc/library_sdk_member.go @@ -380,7 +380,11 @@ func (p *nativeLibInfoProperties) PopulateFromVariant(ctx android.SdkMemberConte // Make sure that the include directories are unique. p.ExportedIncludeDirs = android.FirstUniquePaths(exportedIncludeDirs) p.exportedGeneratedIncludeDirs = android.FirstUniquePaths(exportedGeneratedIncludeDirs) - p.ExportedSystemIncludeDirs = android.FirstUniquePaths(ccModule.ExportedSystemIncludeDirs()) + + // Take a copy before filtering out duplicates to avoid changing the slice owned by the + // ccModule. + dirs := append(android.Paths(nil), ccModule.ExportedSystemIncludeDirs()...) + p.ExportedSystemIncludeDirs = android.FirstUniquePaths(dirs) p.ExportedFlags = ccModule.ExportedFlags() if ccModule.linker != nil { diff --git a/cc/ndk_prebuilt.go b/cc/ndk_prebuilt.go index c4d770837..acdc581a2 100644 --- a/cc/ndk_prebuilt.go +++ b/cc/ndk_prebuilt.go @@ -145,6 +145,7 @@ func NdkPrebuiltStaticStlFactory() android.Module { libraryDecorator: library, } module.installer = nil + module.Properties.Sdk_version = StringPtr("minimum") module.Properties.HideFromMake = true module.Properties.AlwaysSdk = true module.Properties.Sdk_version = StringPtr("current") diff --git a/cc/testing.go b/cc/testing.go index 479b424ab..b5cf45c55 100644 --- a/cc/testing.go +++ b/cc/testing.go @@ -273,6 +273,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { vendor_available: true, recovery_available: true, host_supported: true, + min_sdk_version: "29", apex_available: [ "//apex_available:platform", "//apex_available:anyapex", @@ -287,6 +288,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { vendor_available: true, recovery_available: true, host_supported: true, + min_sdk_version: "29", vndk: { enabled: true, support_system_process: true, @@ -305,6 +307,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { host_supported: false, vendor_available: true, recovery_available: true, + min_sdk_version: "29", apex_available: [ "//apex_available:platform", "//apex_available:anyapex", @@ -338,6 +341,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { recovery_available: true, vendor_available: true, native_bridge_supported: true, + min_sdk_version: "29", stl: "none", } @@ -365,6 +369,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { recovery_available: true, vendor_available: true, native_bridge_supported: true, + min_sdk_version: "29", stl: "none", } diff --git a/dexpreopt/config.go b/dexpreopt/config.go index bc44b2101..4a4e834be 100644 --- a/dexpreopt/config.go +++ b/dexpreopt/config.go @@ -383,7 +383,7 @@ func createGlobalSoongConfig(ctx android.ModuleContext) *GlobalSoongConfig { SoongZip: ctx.Config().HostToolPath(ctx, "soong_zip"), Zip2zip: ctx.Config().HostToolPath(ctx, "zip2zip"), ManifestCheck: ctx.Config().HostToolPath(ctx, "manifest_check"), - ConstructContext: android.PathForSource(ctx, "build/make/core/construct_context.sh"), + ConstructContext: android.PathForSource(ctx, "build/soong/scripts/construct_context.sh"), } } diff --git a/genrule/genrule.go b/genrule/genrule.go index f6904f195..8b8087155 100644 --- a/genrule/genrule.go +++ b/genrule/genrule.go @@ -559,6 +559,12 @@ func (g *Module) AndroidMk() android.AndroidMkData { } } +func (g *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error { + // Because generated outputs are checked by client modules(e.g. cc_library, ...) + // we can safely ignore the check here. + return nil +} + func generatorFactory(taskGenerator taskFunc, props ...interface{}) *Module { module := &Module{ taskGenerator: taskGenerator, diff --git a/java/aar.go b/java/aar.go index 074ead470..500788f48 100644 --- a/java/aar.go +++ b/java/aar.go @@ -762,6 +762,10 @@ func (a *AARImport) DepIsInSameApex(ctx android.BaseModuleContext, dep android.M return a.depIsInSameApex(ctx, dep) } +func (g *AARImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error { + return nil +} + var _ android.PrebuiltInterface = (*Import)(nil) // android_library_import imports an `.aar` file into the build graph as if it was built with android_library. diff --git a/java/androidmk.go b/java/androidmk.go index 62cf169fa..e73b03058 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -91,7 +91,7 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries { } else { mainEntries = android.AndroidMkEntries{ Class: "JAVA_LIBRARIES", - DistFile: android.OptionalPathForPath(library.distFile), + DistFiles: library.distFiles, OutputFile: android.OptionalPathForPath(library.outputFile), Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk", ExtraEntries: []android.AndroidMkExtraEntriesFunc{ @@ -550,14 +550,14 @@ func (dstubs *Droidstubs) AndroidMkEntries() []android.AndroidMkEntries { // needed because an invalid output file would prevent the make entries from // being written. // TODO(b/146727827): Revert when we do not need to generate stubs and API separately. - distFile := android.OptionalPathForPath(dstubs.apiFile) + distFile := dstubs.apiFile outputFile := android.OptionalPathForPath(dstubs.stubsSrcJar) if !outputFile.Valid() { - outputFile = distFile + outputFile = android.OptionalPathForPath(distFile) } return []android.AndroidMkEntries{android.AndroidMkEntries{ Class: "JAVA_LIBRARIES", - DistFile: distFile, + DistFiles: android.MakeDefaultDistFiles(distFile), OutputFile: outputFile, Include: "$(BUILD_SYSTEM)/soong_droiddoc_prebuilt.mk", ExtraEntries: []android.AndroidMkExtraEntriesFunc{ diff --git a/java/androidmk_test.go b/java/androidmk_test.go index d471fb7d5..075b7aa6f 100644 --- a/java/androidmk_test.go +++ b/java/androidmk_test.go @@ -156,17 +156,158 @@ func TestDistWithTag(t *testing.T) { } `) - without_tag_entries := android.AndroidMkEntriesForTest(t, config, "", ctx.ModuleForTests("foo_without_tag", "android_common").Module()) - with_tag_entries := android.AndroidMkEntriesForTest(t, config, "", ctx.ModuleForTests("foo_with_tag", "android_common").Module()) + withoutTagEntries := android.AndroidMkEntriesForTest(t, config, "", ctx.ModuleForTests("foo_without_tag", "android_common").Module()) + withTagEntries := android.AndroidMkEntriesForTest(t, config, "", ctx.ModuleForTests("foo_with_tag", "android_common").Module()) - if len(without_tag_entries) != 2 || len(with_tag_entries) != 2 { - t.Errorf("two mk entries per module expected, got %d and %d", len(without_tag_entries), len(with_tag_entries)) + if len(withoutTagEntries) != 2 || len(withTagEntries) != 2 { + t.Errorf("two mk entries per module expected, got %d and %d", len(withoutTagEntries), len(withTagEntries)) } - if !with_tag_entries[0].DistFile.Valid() || !strings.Contains(with_tag_entries[0].DistFile.String(), "/javac/foo_with_tag.jar") { - t.Errorf("expected classes.jar DistFile, got %v", with_tag_entries[0].DistFile) + if len(withTagEntries[0].DistFiles[".jar"]) != 1 || + !strings.Contains(withTagEntries[0].DistFiles[".jar"][0].String(), "/javac/foo_with_tag.jar") { + t.Errorf("expected DistFiles to contain classes.jar, got %v", withTagEntries[0].DistFiles) } - if without_tag_entries[0].DistFile.Valid() { - t.Errorf("did not expect explicit DistFile, got %v", without_tag_entries[0].DistFile) + if len(withoutTagEntries[0].DistFiles[".jar"]) > 0 { + t.Errorf("did not expect explicit DistFile for .jar tag, got %v", withoutTagEntries[0].DistFiles[".jar"]) + } +} + +func TestDistWithDest(t *testing.T) { + ctx, config := testJava(t, ` + java_library { + name: "foo", + srcs: ["a.java"], + compile_dex: true, + dist: { + targets: ["my_goal"], + dest: "my/custom/dest/dir", + }, + } + `) + + module := ctx.ModuleForTests("foo", "android_common").Module() + entries := android.AndroidMkEntriesForTest(t, config, "", module) + if len(entries) != 2 { + t.Errorf("Expected 2 AndroidMk entries, got %d", len(entries)) + } + + distStrings := entries[0].GetDistForGoals(module) + + if len(distStrings) != 2 { + t.Errorf("Expected 2 entries for dist: PHONY and dist-for-goals, but got %q", distStrings) + } + + if distStrings[0] != ".PHONY: my_goal\n" { + t.Errorf("Expected .PHONY entry to declare my_goal, but got: %s", distStrings[0]) + } + + if !strings.Contains(distStrings[1], "$(call dist-for-goals,my_goal") || + !strings.Contains(distStrings[1], ".intermediates/foo/android_common/dex/foo.jar:my/custom/dest/dir") { + t.Errorf( + "Expected dist-for-goals entry to contain my_goal and new dest dir, but got: %s", distStrings[1]) + } +} + +func TestDistsWithAllProperties(t *testing.T) { + ctx, config := testJava(t, ` + java_library { + name: "foo", + srcs: ["a.java"], + compile_dex: true, + dist: { + targets: ["baz"], + }, + dists: [ + { + targets: ["bar"], + tag: ".jar", + dest: "bar.jar", + dir: "bar/dir", + suffix: ".qux", + }, + ] + } + `) + + module := ctx.ModuleForTests("foo", "android_common").Module() + entries := android.AndroidMkEntriesForTest(t, config, "", module) + if len(entries) != 2 { + t.Errorf("Expected 2 AndroidMk entries, got %d", len(entries)) + } + + distStrings := entries[0].GetDistForGoals(module) + + if len(distStrings) != 4 { + t.Errorf("Expected 4 entries for dist: PHONY and dist-for-goals, but got %d", len(distStrings)) + } + + if distStrings[0] != ".PHONY: bar\n" { + t.Errorf("Expected .PHONY entry to declare bar, but got: %s", distStrings[0]) + } + + if !strings.Contains(distStrings[1], "$(call dist-for-goals,bar") || + !strings.Contains( + distStrings[1], + ".intermediates/foo/android_common/javac/foo.jar:bar/dir/bar.qux.jar") { + t.Errorf( + "Expected dist-for-goals entry to contain bar and new dest dir, but got: %s", distStrings[1]) + } + + if distStrings[2] != ".PHONY: baz\n" { + t.Errorf("Expected .PHONY entry to declare baz, but got: %s", distStrings[2]) + } + + if !strings.Contains(distStrings[3], "$(call dist-for-goals,baz") || + !strings.Contains(distStrings[3], ".intermediates/foo/android_common/dex/foo.jar:foo.jar") { + t.Errorf( + "Expected dist-for-goals entry to contain my_other_goal and new dest dir, but got: %s", + distStrings[3]) + } +} + +func TestDistsWithTag(t *testing.T) { + ctx, config := testJava(t, ` + java_library { + name: "foo_without_tag", + srcs: ["a.java"], + compile_dex: true, + dists: [ + { + targets: ["hi"], + }, + ], + } + java_library { + name: "foo_with_tag", + srcs: ["a.java"], + compile_dex: true, + dists: [ + { + targets: ["hi"], + tag: ".jar", + }, + ], + } + `) + + moduleWithoutTag := ctx.ModuleForTests("foo_without_tag", "android_common").Module() + moduleWithTag := ctx.ModuleForTests("foo_with_tag", "android_common").Module() + + withoutTagEntries := android.AndroidMkEntriesForTest(t, config, "", moduleWithoutTag) + withTagEntries := android.AndroidMkEntriesForTest(t, config, "", moduleWithTag) + + if len(withoutTagEntries) != 2 || len(withTagEntries) != 2 { + t.Errorf("two mk entries per module expected, got %d and %d", len(withoutTagEntries), len(withTagEntries)) + } + + distFilesWithoutTag := withoutTagEntries[0].DistFiles + distFilesWithTag := withTagEntries[0].DistFiles + + if len(distFilesWithTag[".jar"]) != 1 || + !strings.Contains(distFilesWithTag[".jar"][0].String(), "/javac/foo_with_tag.jar") { + t.Errorf("expected foo_with_tag's .jar-tagged DistFiles to contain classes.jar, got %v", distFilesWithTag[".jar"]) + } + if len(distFilesWithoutTag[".jar"]) > 0 { + t.Errorf("did not expect foo_without_tag's .jar-tagged DistFiles to contain files, but got %v", distFilesWithoutTag[".jar"]) } } diff --git a/java/app.go b/java/app.go index c568516eb..37a6453cd 100755 --- a/java/app.go +++ b/java/app.go @@ -421,8 +421,10 @@ func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) { if String(a.deviceProperties.Min_sdk_version) == "" { ctx.PropertyErrorf("updatable", "updatable apps must set min_sdk_version.") } + if minSdkVersion, err := a.minSdkVersion().effectiveVersion(ctx); err == nil { a.checkJniLibsSdkVersion(ctx, minSdkVersion) + android.CheckMinSdkVersion(a, ctx, int(minSdkVersion)) } else { ctx.PropertyErrorf("min_sdk_version", "%s", err.Error()) } @@ -862,13 +864,13 @@ func collectAppDeps(ctx android.ModuleContext, app appDepsInterface, return jniLibs, certificates } -func (a *AndroidApp) walkPayloadDeps(ctx android.ModuleContext, - do func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool)) { - +func (a *AndroidApp) WalkPayloadDeps(ctx android.ModuleContext, do android.PayloadDepsCallback) { ctx.WalkDeps(func(child, parent android.Module) bool { isExternal := !a.DepIsInSameApex(ctx, child) if am, ok := child.(android.ApexModule); ok { - do(ctx, parent, am, isExternal) + if !do(ctx, parent, am, isExternal) { + return false + } } return !isExternal }) @@ -880,7 +882,7 @@ func (a *AndroidApp) buildAppDependencyInfo(ctx android.ModuleContext) { } depsInfo := android.DepNameToDepInfoMap{} - a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) { + a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool { depName := to.Name() if info, exist := depsInfo[depName]; exist { info.From = append(info.From, from.Name()) @@ -900,6 +902,7 @@ func (a *AndroidApp) buildAppDependencyInfo(ctx android.ModuleContext) { MinSdkVersion: toMinSdkVersion, } } + return true }) a.ApexBundleDepsInfo.BuildDepsInfoLists(ctx, a.MinSdkVersion(), depsInfo) @@ -1563,6 +1566,11 @@ func (a *AndroidAppImport) minSdkVersion() sdkSpec { return sdkSpecFrom("") } +func (j *AndroidAppImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error { + // Do not check for prebuilts against the min_sdk_version of enclosing APEX + return nil +} + func createVariantGroupType(variants []string, variantGroupName string) reflect.Type { props := reflect.TypeOf((*AndroidAppImportProperties)(nil)) diff --git a/java/app_test.go b/java/app_test.go index e45ba70d5..120dc00a6 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -473,6 +473,24 @@ func TestUpdatableApps(t *testing.T) { } } +func TestUpdatableApps_TransitiveDepsShouldSetMinSdkVersion(t *testing.T) { + testJavaError(t, `module "bar".*: should support min_sdk_version\(29\)`, cc.GatherRequiredDepsForTest(android.Android)+` + android_app { + name: "foo", + srcs: ["a.java"], + updatable: true, + sdk_version: "current", + min_sdk_version: "29", + static_libs: ["bar"], + } + + java_library { + name: "bar", + sdk_version: "current", + } + `) +} + func TestUpdatableApps_JniLibsShouldShouldSupportMinSdkVersion(t *testing.T) { testJava(t, cc.GatherRequiredDepsForTest(android.Android)+` android_app { diff --git a/java/config/config.go b/java/config/config.go index bb5be3aca..23b593a82 100644 --- a/java/config/config.go +++ b/java/config/config.go @@ -35,7 +35,8 @@ var ( DefaultLambdaStubsLibrary = "core-lambda-stubs" SdkLambdaStubsPath = "prebuilts/sdk/tools/core-lambda-stubs.jar" - DefaultJacocoExcludeFilter = []string{"org.junit.*", "org.jacoco.*", "org.mockito.*"} + DefaultMakeJacocoExcludeFilter = []string{"org.junit.*", "org.jacoco.*", "org.mockito.*"} + DefaultJacocoExcludeFilter = []string{"org.junit.**", "org.jacoco.**", "org.mockito.**"} InstrumentFrameworkModules = []string{ "framework", diff --git a/java/config/makevars.go b/java/config/makevars.go index 981a73638..b355fad87 100644 --- a/java/config/makevars.go +++ b/java/config/makevars.go @@ -64,7 +64,7 @@ func makeVarsProvider(ctx android.MakeVarsContext) { ctx.Strict("ZIPSYNC", "${ZipSyncCmd}") ctx.Strict("JACOCO_CLI_JAR", "${JacocoCLIJar}") - ctx.Strict("DEFAULT_JACOCO_EXCLUDE_FILTER", strings.Join(DefaultJacocoExcludeFilter, ",")) + ctx.Strict("DEFAULT_JACOCO_EXCLUDE_FILTER", strings.Join(DefaultMakeJacocoExcludeFilter, ",")) ctx.Strict("EXTRACT_JAR_PACKAGES", "${ExtractJarPackagesCmd}") diff --git a/java/dexpreopt.go b/java/dexpreopt.go index 7f1afd667..f1b717874 100644 --- a/java/dexpreopt.go +++ b/java/dexpreopt.go @@ -173,7 +173,7 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo profileBootListing = android.ExistentPathForSource(ctx, ctx.ModuleDir(), String(d.dexpreoptProperties.Dex_preopt.Profile)+"-boot") profileIsTextListing = true - } else { + } else if global.ProfileDir != "" { profileClassListing = android.ExistentPathForSource(ctx, global.ProfileDir, ctx.ModuleName()+".prof") } diff --git a/java/droiddoc.go b/java/droiddoc.go index a0b7edfea..73b897ad0 100644 --- a/java/droiddoc.go +++ b/java/droiddoc.go @@ -1325,7 +1325,6 @@ func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuil cmd.Flag("--exclude-documentation-from-stubs") } } - cmd.FlagWithArg("--hide ", "ShowingMemberInHiddenClass") // b/159121253 -- remove it once all the violations are fixed. } func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) { diff --git a/java/jacoco.go b/java/jacoco.go index bce9822f4..9162161d3 100644 --- a/java/jacoco.go +++ b/java/jacoco.go @@ -25,6 +25,7 @@ import ( "github.com/google/blueprint/proptools" "android/soong/android" + "android/soong/java/config" ) var ( @@ -76,7 +77,8 @@ func (j *Module) jacocoModuleToZipCommand(ctx android.ModuleContext) string { if err != nil { ctx.PropertyErrorf("jacoco.include_filter", "%s", err.Error()) } - excludes, err := jacocoFiltersToSpecs(j.properties.Jacoco.Exclude_filter) + // Also include the default list of classes to exclude from instrumentation. + excludes, err := jacocoFiltersToSpecs(append(j.properties.Jacoco.Exclude_filter, config.DefaultJacocoExcludeFilter...)) if err != nil { ctx.PropertyErrorf("jacoco.exclude_filter", "%s", err.Error()) } diff --git a/java/java.go b/java/java.go index 7a4255745..0a8eb992c 100644 --- a/java/java.go +++ b/java/java.go @@ -44,7 +44,7 @@ func init() { PropertyName: "java_libs", }, func(j *Library) android.Path { - implementationJars := j.ImplementationJars() + implementationJars := j.ImplementationAndResourcesJars() if len(implementationJars) != 1 { panic(fmt.Errorf("there must be only one implementation jar from %q", j.Name())) } @@ -479,7 +479,7 @@ type Module struct { // list of the xref extraction files kytheFiles android.Paths - distFile android.Path + distFiles android.TaggedDistFiles // Collect the module directory for IDE info in java/jdeps.go. modulePaths []string @@ -1887,6 +1887,24 @@ func (j *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Modu return j.depIsInSameApex(ctx, dep) } +func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error { + sdkSpec := j.minSdkVersion() + if !sdkSpec.specified() { + return fmt.Errorf("min_sdk_version is not specified") + } + if sdkSpec.kind == sdkCore { + return nil + } + ver, err := sdkSpec.effectiveVersion(ctx) + if err != nil { + return err + } + if int(ver) > sdkVersion { + return fmt.Errorf("newer SDK(%v)", ver) + } + return nil +} + func (j *Module) Stem() string { return proptools.StringDefault(j.deviceProperties.Stem, j.Name()) } @@ -1903,18 +1921,9 @@ func (j *Module) IsInstallable() bool { // Java libraries (.jar file) // -type LibraryProperties struct { - Dist struct { - // The tag of the output of this module that should be output. - Tag *string `android:"arch_variant"` - } `android:"arch_variant"` -} - type Library struct { Module - libraryProperties LibraryProperties - InstallMixin func(ctx android.ModuleContext, installPath android.Path) (extraInstallDeps android.Paths) } @@ -1976,14 +1985,7 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.Stem()+".jar", j.outputFile, extraInstallDeps...) } - // Verify Dist.Tag is set to a supported output - if j.libraryProperties.Dist.Tag != nil { - distFiles, err := j.OutputFiles(*j.libraryProperties.Dist.Tag) - if err != nil { - ctx.PropertyErrorf("dist.tag", "%s", err.Error()) - } - j.distFile = distFiles[0] - } + j.distFiles = j.GenerateTaggedDistFiles(ctx) } func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) { @@ -2101,7 +2103,6 @@ func LibraryFactory() android.Module { module := &Library{} module.addHostAndDeviceProperties() - module.AddProperties(&module.libraryProperties) module.initModuleAndImport(&module.ModuleBase) @@ -2651,6 +2652,11 @@ func (j *Import) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Modu return j.depIsInSameApex(ctx, dep) } +func (j *Import) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error { + // Do not check for prebuilts against the min_sdk_version of enclosing APEX + return nil +} + // Add compile time check for interface implementation var _ android.IDEInfo = (*Import)(nil) var _ android.IDECustomizedModuleName = (*Import)(nil) @@ -2820,6 +2826,11 @@ func (j *DexImport) DexJarBuildPath() android.Path { return j.dexJarFile } +func (j *DexImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error { + // we don't check prebuilt modules for sdk_version + return nil +} + // dex_import imports a `.jar` file containing classes.dex files. // // A dex_import module cannot be used as a dependency of a java_* or android_* module, it can only be installed diff --git a/java/sdk_library.go b/java/sdk_library.go index 676557e64..91869ed57 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -1905,6 +1905,11 @@ func (module *SdkLibraryImport) DepIsInSameApex(mctx android.BaseModuleContext, return false } +func (module *SdkLibraryImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error { + // we don't check prebuilt modules for sdk_version + return nil +} + func (module *SdkLibraryImport) OutputFiles(tag string) (android.Paths, error) { return module.commonOutputFiles(tag) } @@ -2071,6 +2076,11 @@ func (module *sdkLibraryXml) DepsMutator(ctx android.BottomUpMutatorContext) { // do nothing } +func (module *sdkLibraryXml) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error { + // sdkLibraryXml doesn't need to be checked separately because java_sdk_library is checked + return nil +} + // File path to the runtime implementation library func (module *sdkLibraryXml) implPath() string { implName := proptools.String(module.properties.Lib_name) diff --git a/rust/OWNERS b/rust/OWNERS index afd06e422..b5b795c1a 100644 --- a/rust/OWNERS +++ b/rust/OWNERS @@ -1,5 +1,5 @@ # Additional owner/reviewers for rust rules, including parent directory owners. -per-file * = chh@google.com, ivanlozano@google.com, jeffv@google.com, srhines@google.com +per-file * = chh@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 = chh@google.com, ivanlozano@google.com, jeffv@google.com, jgalenson@google.com, srhines@google.com +per-file allowed_list.go = chh@google.com, ivanlozano@google.com, jeffv@google.com, jgalenson@google.com, mmaurer@google.com, srhines@google.com diff --git a/rust/androidmk.go b/rust/androidmk.go index 69d0df562..aea899baa 100644 --- a/rust/androidmk.go +++ b/rust/androidmk.go @@ -86,8 +86,11 @@ func (mod *Module) AndroidMk() android.AndroidMkData { func (binary *binaryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { ctx.subAndroidMk(ret, binary.baseCompiler) + if binary.distFile.Valid() { + ret.DistFiles = android.MakeDefaultDistFiles(binary.distFile.Path()) + } + ret.Class = "EXECUTABLES" - ret.DistFile = binary.distFile ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) { fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", binary.unstrippedOutputFile.String()) if binary.coverageOutputZipFile.Valid() { @@ -127,7 +130,10 @@ func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.An ret.Class = "SHARED_LIBRARIES" } - ret.DistFile = library.distFile + if library.distFile.Valid() { + ret.DistFiles = android.MakeDefaultDistFiles(library.distFile.Path()) + } + ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) { if !library.rlib() { fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", library.unstrippedOutputFile.String()) @@ -143,7 +149,9 @@ func (procMacro *procMacroDecorator) AndroidMk(ctx AndroidMkContext, ret *androi ctx.subAndroidMk(ret, procMacro.baseCompiler) ret.Class = "PROC_MACRO_LIBRARIES" - ret.DistFile = procMacro.distFile + if procMacro.distFile.Valid() { + ret.DistFiles = android.MakeDefaultDistFiles(procMacro.distFile.Path()) + } } diff --git a/rust/config/global.go b/rust/config/global.go index 63624c03e..663514d46 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.43.0" + RustDefaultVersion = "1.44.0" RustDefaultBase = "prebuilts/rust/" DefaultEdition = "2018" Stdlibs = []string{ diff --git a/rust/rust_test.go b/rust/rust_test.go index 703aaed29..280c22a7e 100644 --- a/rust/rust_test.go +++ b/rust/rust_test.go @@ -93,7 +93,6 @@ func testRustContext(t *testing.T, bp string, coverage bool) *android.TestContex config.TestProductVariables.NativeCoveragePaths = []string{"*"} } - t.Helper() ctx := CreateTestContext() ctx.Register(config) diff --git a/scripts/OWNERS b/scripts/OWNERS index dd0966fa5..027455484 100644 --- a/scripts/OWNERS +++ b/scripts/OWNERS @@ -1,3 +1,4 @@ per-file system-clang-format,system-clang-format-2 = enh@google.com,smoreland@google.com per-file build-mainline-modules.sh = ngeoffray@google.com,paulduffin@google.com,mast@google.com per-file build-aml-prebuilts.sh = ngeoffray@google.com,paulduffin@google.com,mast@google.com +per-file construct_context.sh = ngeoffray@google.com,calin@google.com,mathieuc@google.com,skvadrik@google.com diff --git a/scripts/build-mainline-modules.sh b/scripts/build-mainline-modules.sh index 9b68a82c7..0520d31e6 100755 --- a/scripts/build-mainline-modules.sh +++ b/scripts/build-mainline-modules.sh @@ -23,6 +23,14 @@ MODULES_SDK_AND_EXPORTS=( runtime-module-host-exports i18n-module-test-exports i18n-module-sdk + platform-mainline-sdk +) + +# List of libraries installed on the platform that are needed for ART chroot +# testing. +PLATFORM_LIBRARIES=( + liblog + libartpalette-system ) # We want to create apex modules for all supported architectures. @@ -49,7 +57,8 @@ DIST_DIR=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT= get_build_var D for product in "${PRODUCTS[@]}"; do echo_and_run build/soong/soong_ui.bash --make-mode $@ \ TARGET_PRODUCT=${product} \ - ${MAINLINE_MODULES[@]} + ${MAINLINE_MODULES[@]} \ + ${PLATFORM_LIBRARIES[@]} PRODUCT_OUT=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT=${product} get_build_var PRODUCT_OUT) TARGET_ARCH=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT=${product} get_build_var TARGET_ARCH) @@ -58,9 +67,11 @@ for product in "${PRODUCTS[@]}"; do for module in "${MAINLINE_MODULES[@]}"; do echo_and_run cp ${PWD}/${PRODUCT_OUT}/system/apex/${module}.apex ${DIST_DIR}/${TARGET_ARCH}/ done + for library in "${PLATFORM_LIBRARIES[@]}"; do + echo_and_run cp ${PWD}/${PRODUCT_OUT}/system/lib/${library}.so ${DIST_DIR}/${TARGET_ARCH}/ + done done - # Create multi-archs SDKs in a different out directory. The multi-arch script # uses Soong in --skip-make mode which cannot use the same directory as normal # mode with make. diff --git a/scripts/construct_context.sh b/scripts/construct_context.sh new file mode 100755 index 000000000..d620d0846 --- /dev/null +++ b/scripts/construct_context.sh @@ -0,0 +1,78 @@ +#!/bin/bash +# +# Copyright (C) 2018 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -e + +# target_sdk_version: parsed from manifest +# +# outputs +# class_loader_context_arg: final class loader conext arg +# stored_class_loader_context_arg: final stored class loader context arg + +if [ -z "${target_sdk_version}" ]; then + echo "ERROR: target_sdk_version not set" + exit 2 +fi + +# The hidl.manager shared library has a dependency on hidl.base. We'll manually +# add that information to the class loader context if we see those libraries. +hidl_manager="android.hidl.manager-V1.0-java" +hidl_base="android.hidl.base-V1.0-java" + +function add_to_contexts { + for i in $1; do + if [[ -z "${class_loader_context}" ]]; then + export class_loader_context="PCL[$i]" + else + export class_loader_context+="#PCL[$i]" + fi + if [[ $i == *"$hidl_manager"* ]]; then + export class_loader_context+="{PCL[${i/$hidl_manager/$hidl_base}]}" + fi + done + + for i in $2; do + if [[ -z "${stored_class_loader_context}" ]]; then + export stored_class_loader_context="PCL[$i]" + else + export stored_class_loader_context+="#PCL[$i]" + fi + if [[ $i == *"$hidl_manager"* ]]; then + export stored_class_loader_context+="{PCL[${i/$hidl_manager/$hidl_base}]}" + fi + done +} + +# The order below must match what the package manager also computes for +# class loader context. + +if [[ "${target_sdk_version}" -lt "28" ]]; then + add_to_contexts "${conditional_host_libs_28}" "${conditional_target_libs_28}" +fi + +if [[ "${target_sdk_version}" -lt "29" ]]; then + add_to_contexts "${conditional_host_libs_29}" "${conditional_target_libs_29}" +fi + +if [[ "${target_sdk_version}" -lt "30" ]]; then + add_to_contexts "${conditional_host_libs_30}" "${conditional_target_libs_30}" +fi + +add_to_contexts "${dex_preopt_host_libraries}" "${dex_preopt_target_libraries}" + +# Generate the actual context string. +export class_loader_context_arg="--class-loader-context=PCL[]{${class_loader_context}}" +export stored_class_loader_context_arg="--stored-class-loader-context=PCL[]{${stored_class_loader_context}}" diff --git a/scripts/rustfmt.toml b/scripts/rustfmt.toml new file mode 100644 index 000000000..617d42585 --- /dev/null +++ b/scripts/rustfmt.toml @@ -0,0 +1,5 @@ +# Android Format Style + +edition = "2018" +use_small_heuristics = "Max" +newline_style = "Unix" diff --git a/scripts/transitive-deps.sh b/scripts/transitive-deps.sh index c6f8b76e4..ba36ba4bf 100755 --- a/scripts/transitive-deps.sh +++ b/scripts/transitive-deps.sh @@ -56,7 +56,7 @@ Output Options: temporary / intermediate files. -sep=<delim> Use 'delim' as output field separator between notice checksum and notice filename in notice output. - e.g. sep='\t' + e.g. sep='\\t' (Default space) -csv Shorthand for -sep=',' -directories=<f> Output directory names of dependencies to 'f'. @@ -280,7 +280,7 @@ while [ $# -gt 0 ]; do notices=) notices_out=$(expr "${flag}" : '^.*=\(.*\)$');; *) - die "Unknown flag ${1}";; + die "${usage}\n\nUnknown flag ${1}";; esac ;; *) diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go index 77a4e94b3..7496b207d 100644 --- a/sdk/java_sdk_test.go +++ b/sdk/java_sdk_test.go @@ -23,6 +23,7 @@ func testSdkWithJava(t *testing.T, bp string) *testSdkResult { fs := map[string][]byte{ "Test.java": nil, + "resource.test": nil, "aidl/foo/bar/Test.aidl": nil, // For java_sdk_library @@ -348,6 +349,7 @@ func TestSnapshotWithJavaImplLibrary(t *testing.T) { java_library { name: "myjavalib", srcs: ["Test.java"], + java_resources: ["resource.txt"], aidl: { export_include_dirs: ["aidl"], }, @@ -381,7 +383,7 @@ module_exports_snapshot { `), checkAllCopyRules(` -.intermediates/myjavalib/android_common/javac/myjavalib.jar -> java/myjavalib.jar +.intermediates/myjavalib/android_common/withres/myjavalib.jar -> java/myjavalib.jar aidl/foo/bar/Test.aidl -> aidl/aidl/foo/bar/Test.aidl `), ) diff --git a/sdk/sdk.go b/sdk/sdk.go index cb5a6053d..b9b8199d3 100644 --- a/sdk/sdk.go +++ b/sdk/sdk.go @@ -291,7 +291,7 @@ func (s *sdk) AndroidMkEntries() []android.AndroidMkEntries { return []android.AndroidMkEntries{android.AndroidMkEntries{ Class: "FAKE", OutputFile: s.snapshotFile, - DistFile: s.snapshotFile, + DistFiles: android.MakeDefaultDistFiles(s.snapshotFile.Path()), Include: "$(BUILD_PHONY_PACKAGE)", ExtraFooters: []android.AndroidMkExtraFootersFunc{ func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) { diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go index 9f27647a0..768c8e5b0 100644 --- a/sysprop/sysprop_library.go +++ b/sysprop/sysprop_library.go @@ -310,6 +310,10 @@ func (m *syspropLibrary) AndroidMk() android.AndroidMkData { }} } +func (m *syspropLibrary) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error { + return fmt.Errorf("sysprop_library is not supposed to be part of apex modules") +} + // sysprop_library creates schematized APIs from sysprop description files (.sysprop). // Both Java and C++ modules can link against sysprop_library, and API stability check // against latest APIs (see build/soong/scripts/freeze-sysprop-api-files.sh) diff --git a/ui/build/build.go b/ui/build/build.go index 89c3fad20..396f54cda 100644 --- a/ui/build/build.go +++ b/ui/build/build.go @@ -243,6 +243,8 @@ func Build(ctx Context, config Config, what int) { // Write combined ninja file createCombinedBuildNinjaFile(ctx, config) + distGzipFile(ctx, config, config.CombinedNinjaFile()) + if what&RunBuildTests != 0 { testForDanglingRules(ctx, config) } @@ -256,3 +258,47 @@ func Build(ctx Context, config Config, what int) { runNinja(ctx, config) } } + +// distGzipFile writes a compressed copy of src to the distDir if dist is enabled. Failures +// are printed but non-fatal. +func distGzipFile(ctx Context, config Config, src string, subDirs ...string) { + if !config.Dist() { + return + } + + subDir := filepath.Join(subDirs...) + destDir := filepath.Join(config.DistDir(), "soong_ui", subDir) + + err := os.MkdirAll(destDir, 0777) + if err != nil { + ctx.Printf("failed to mkdir %s: %s", destDir, err.Error()) + + } + + err = gzipFileToDir(src, destDir) + if err != nil { + ctx.Printf("failed to dist %s: %s", filepath.Base(src), err.Error()) + } +} + +// distFile writes a copy of src to the distDir if dist is enabled. Failures are printed but +// non-fatal. +func distFile(ctx Context, config Config, src string, subDirs ...string) { + if !config.Dist() { + return + } + + subDir := filepath.Join(subDirs...) + destDir := filepath.Join(config.DistDir(), "soong_ui", subDir) + + err := os.MkdirAll(destDir, 0777) + if err != nil { + ctx.Printf("failed to mkdir %s: %s", destDir, err.Error()) + + } + + _, err = copyFile(src, filepath.Join(destDir, filepath.Base(src))) + if err != nil { + ctx.Printf("failed to dist %s: %s", filepath.Base(src), err.Error()) + } +} diff --git a/ui/build/finder.go b/ui/build/finder.go index 0f34b5e70..6786337be 100644 --- a/ui/build/finder.go +++ b/ui/build/finder.go @@ -86,7 +86,7 @@ func FindSources(ctx Context, config Config, f *finder.Finder) { os.MkdirAll(dumpDir, 0777) androidMks := f.FindFirstNamedAt(".", "Android.mk") - err := dumpListToFile(androidMks, filepath.Join(dumpDir, "Android.mk.list")) + err := dumpListToFile(ctx, config, androidMks, filepath.Join(dumpDir, "Android.mk.list")) if err != nil { ctx.Fatalf("Could not export module list: %v", err) } @@ -94,25 +94,25 @@ func FindSources(ctx Context, config Config, f *finder.Finder) { androidProductsMks := f.FindNamedAt("device", "AndroidProducts.mk") androidProductsMks = append(androidProductsMks, f.FindNamedAt("vendor", "AndroidProducts.mk")...) androidProductsMks = append(androidProductsMks, f.FindNamedAt("product", "AndroidProducts.mk")...) - err = dumpListToFile(androidProductsMks, filepath.Join(dumpDir, "AndroidProducts.mk.list")) + err = dumpListToFile(ctx, config, androidProductsMks, filepath.Join(dumpDir, "AndroidProducts.mk.list")) if err != nil { ctx.Fatalf("Could not export product list: %v", err) } cleanSpecs := f.FindFirstNamedAt(".", "CleanSpec.mk") - err = dumpListToFile(cleanSpecs, filepath.Join(dumpDir, "CleanSpec.mk.list")) + err = dumpListToFile(ctx, config, cleanSpecs, filepath.Join(dumpDir, "CleanSpec.mk.list")) if err != nil { ctx.Fatalf("Could not export module list: %v", err) } owners := f.FindNamedAt(".", "OWNERS") - err = dumpListToFile(owners, filepath.Join(dumpDir, "OWNERS.list")) + err = dumpListToFile(ctx, config, owners, filepath.Join(dumpDir, "OWNERS.list")) if err != nil { ctx.Fatalf("Could not find OWNERS: %v", err) } testMappings := f.FindNamedAt(".", "TEST_MAPPING") - err = dumpListToFile(testMappings, filepath.Join(dumpDir, "TEST_MAPPING.list")) + err = dumpListToFile(ctx, config, testMappings, filepath.Join(dumpDir, "TEST_MAPPING.list")) if err != nil { ctx.Fatalf("Could not find TEST_MAPPING: %v", err) } @@ -122,18 +122,24 @@ func FindSources(ctx Context, config Config, f *finder.Finder) { if len(androidBps) == 0 { ctx.Fatalf("No Android.bp found") } - err = dumpListToFile(androidBps, filepath.Join(dumpDir, "Android.bp.list")) + err = dumpListToFile(ctx, config, androidBps, filepath.Join(dumpDir, "Android.bp.list")) if err != nil { ctx.Fatalf("Could not find modules: %v", err) } } -func dumpListToFile(list []string, filePath string) (err error) { +func dumpListToFile(ctx Context, config Config, list []string, filePath string) (err error) { desiredText := strings.Join(list, "\n") desiredBytes := []byte(desiredText) actualBytes, readErr := ioutil.ReadFile(filePath) if readErr != nil || !bytes.Equal(desiredBytes, actualBytes) { err = ioutil.WriteFile(filePath, desiredBytes, 0777) + if err != nil { + return err + } } - return err + + distFile(ctx, config, filePath, "module_paths") + + return nil } diff --git a/ui/build/kati.go b/ui/build/kati.go index 2eb785032..1cd5fea32 100644 --- a/ui/build/kati.go +++ b/ui/build/kati.go @@ -156,6 +156,8 @@ func runKatiBuild(ctx Context, config Config) { runKati(ctx, config, katiBuildSuffix, args, func(env *Environment) {}) + distGzipFile(ctx, config, config.KatiBuildNinjaFile()) + cleanCopyHeaders(ctx, config) cleanOldInstalledFiles(ctx, config) } @@ -251,6 +253,8 @@ func runKatiPackage(ctx Context, config Config) { env.Set("DIST_DIR", config.DistDir()) } }) + + distGzipFile(ctx, config, config.KatiPackageNinjaFile()) } func runKatiCleanSpec(ctx Context, config Config) { diff --git a/ui/build/soong.go b/ui/build/soong.go index 6a12add78..749acb3d5 100644 --- a/ui/build/soong.go +++ b/ui/build/soong.go @@ -139,6 +139,13 @@ func runSoong(ctx Context, config Config) { soongBuildMetrics := loadSoongBuildMetrics(ctx, config) logSoongBuildMetrics(ctx, soongBuildMetrics) + distGzipFile(ctx, config, config.SoongNinjaFile(), "soong") + + if !config.SkipMake() { + distGzipFile(ctx, config, config.SoongAndroidMk(), "soong") + distGzipFile(ctx, config, config.SoongMakeVarsMk(), "soong") + } + if ctx.Metrics != nil { ctx.Metrics.SetSoongBuildMetrics(soongBuildMetrics) } diff --git a/ui/build/util.go b/ui/build/util.go index d44cd6daf..d4c3431e9 100644 --- a/ui/build/util.go +++ b/ui/build/util.go @@ -15,6 +15,8 @@ package build import ( + "compress/gzip" + "fmt" "io" "os" "path/filepath" @@ -142,3 +144,29 @@ func copyFile(src, dst string) (int64, error) { return io.Copy(destination, source) } + +// gzipFileToDir writes a compressed copy of src to destDir with the suffix ".gz". +func gzipFileToDir(src, destDir string) error { + in, err := os.Open(src) + if err != nil { + return fmt.Errorf("failed to open %s: %s", src, err.Error()) + } + defer in.Close() + + dest := filepath.Join(destDir, filepath.Base(src)+".gz") + + out, err := os.OpenFile(dest, os.O_CREATE|os.O_WRONLY, 0666) + if err != nil { + return fmt.Errorf("failed to open %s: %s", dest, err.Error()) + } + defer out.Close() + gz := gzip.NewWriter(out) + defer gz.Close() + + _, err = io.Copy(gz, in) + if err != nil { + return fmt.Errorf("failed to gzip %s: %s", dest, err.Error()) + } + + return nil +} |