diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-02-03 19:59:59 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-02-03 19:59:59 +0000 |
commit | 1a6d55f949f3599a51a1b5c253be8d143dec99fe (patch) | |
tree | 5a4175d1e905d066e2a5df8575b29d8c84607a89 | |
parent | 8710ea81d6a6bfcb702519738628991216c6fa38 (diff) | |
parent | d9100a56e64541c340ffb8c72fe04db95b6fd6a8 (diff) | |
download | soong-android12-mainline-neuralnetworks-release.tar.gz |
Snap for 8146243 from d9100a56e64541c340ffb8c72fe04db95b6fd6a8 to mainline-neuralnetworks-releaseandroid-mainline-12.0.0_r92android12-mainline-neuralnetworks-release
Change-Id: Idfe291bde90fe74f17c200a54a119bd3dd037f16
-rw-r--r-- | android/Android.bp | 1 | ||||
-rw-r--r-- | android/apex.go | 20 | ||||
-rw-r--r-- | android/api_levels.go | 16 | ||||
-rw-r--r-- | android/config.go | 10 | ||||
-rw-r--r-- | android/neverallow.go | 65 | ||||
-rw-r--r-- | android/neverallow_test.go | 49 | ||||
-rw-r--r-- | android/sdk_version.go | 8 | ||||
-rw-r--r-- | android/sdk_version_test.go | 89 | ||||
-rw-r--r-- | apex/androidmk.go | 29 | ||||
-rw-r--r-- | apex/apex.go | 51 | ||||
-rw-r--r-- | apex/apex_test.go | 298 | ||||
-rw-r--r-- | apex/builder.go | 150 | ||||
-rw-r--r-- | apex/testing.go | 1 | ||||
-rw-r--r-- | bpf/bpf.go | 16 | ||||
-rw-r--r-- | dexpreopt/testing.go | 8 | ||||
-rwxr-xr-x | java/app.go | 2 | ||||
-rw-r--r-- | java/base.go | 15 | ||||
-rw-r--r-- | java/classpath_fragment.go | 65 | ||||
-rw-r--r-- | java/config/config.go | 2 | ||||
-rw-r--r-- | java/dex.go | 52 | ||||
-rw-r--r-- | java/java.go | 1 | ||||
-rw-r--r-- | java/platform_bootclasspath.go | 1 | ||||
-rw-r--r-- | java/sdk_library.go | 24 | ||||
-rw-r--r-- | java/sdk_library_test.go | 93 | ||||
-rw-r--r-- | java/systemserver_classpath_fragment.go | 26 | ||||
-rw-r--r-- | java/systemserver_classpath_fragment_test.go | 2 | ||||
-rw-r--r-- | rust/rust.go | 10 | ||||
-rw-r--r-- | scripts/OWNERS | 2 | ||||
-rwxr-xr-x | scripts/gen_java_usedby_apex.sh | 48 | ||||
-rw-r--r-- | sdk/sdk.go | 8 |
30 files changed, 945 insertions, 217 deletions
diff --git a/android/Android.bp b/android/Android.bp index 5d0f2b941..36b2670d5 100644 --- a/android/Android.bp +++ b/android/Android.bp @@ -110,6 +110,7 @@ bootstrap_go_package { "paths_test.go", "prebuilt_test.go", "rule_builder_test.go", + "sdk_version_test.go", "singleton_module_test.go", "soong_config_modules_test.go", "util_test.go", diff --git a/android/apex.go b/android/apex.go index 4618fe97e..b5d96e4ae 100644 --- a/android/apex.go +++ b/android/apex.go @@ -903,16 +903,18 @@ var minSdkVersionAllowlist = func(apiMap map[string]int) map[string]ApiLevel { // // Return true if the `to` module should be visited, false otherwise. type PayloadDepsCallback func(ctx ModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool +type WalkPayloadDepsFunc func(ctx ModuleContext, do PayloadDepsCallback) -// UpdatableModule represents updatable APEX/APK -type UpdatableModule interface { +// ModuleWithMinSdkVersionCheck represents a module that implements min_sdk_version checks +type ModuleWithMinSdkVersionCheck interface { Module - WalkPayloadDeps(ctx ModuleContext, do PayloadDepsCallback) + MinSdkVersion(ctx EarlyModuleContext) SdkSpec + CheckMinSdkVersion(ctx ModuleContext) } // CheckMinSdkVersion checks if every dependency of an updatable module sets min_sdk_version // accordingly -func CheckMinSdkVersion(m UpdatableModule, ctx ModuleContext, minSdkVersion ApiLevel) { +func CheckMinSdkVersion(ctx ModuleContext, minSdkVersion ApiLevel, walk WalkPayloadDepsFunc) { // do not enforce min_sdk_version for host if ctx.Host() { return @@ -928,7 +930,7 @@ func CheckMinSdkVersion(m UpdatableModule, ctx ModuleContext, minSdkVersion ApiL return } - m.WalkPayloadDeps(ctx, func(ctx ModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool { + walk(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 @@ -938,6 +940,14 @@ func CheckMinSdkVersion(m UpdatableModule, ctx ModuleContext, minSdkVersion ApiL if am, ok := from.(DepIsInSameApex); ok && !am.DepIsInSameApex(ctx, to) { return false } + if m, ok := to.(ModuleWithMinSdkVersionCheck); ok { + // This dependency performs its own min_sdk_version check, just make sure it sets min_sdk_version + // to trigger the check. + if !m.MinSdkVersion(ctx).Specified() { + ctx.OtherModuleErrorf(m, "must set min_sdk_version") + } + return false + } if err := to.ShouldSupportSdkVersion(ctx, minSdkVersion); err != nil { toName := ctx.OtherModuleName(to) if ver, ok := minSdkVersionAllowlist[toName]; !ok || ver.GreaterThan(minSdkVersion) { diff --git a/android/api_levels.go b/android/api_levels.go index 93583bc07..fe3f41753 100644 --- a/android/api_levels.go +++ b/android/api_levels.go @@ -188,8 +188,8 @@ var FirstNonLibAndroidSupportVersion = uncheckedFinalApiLevel(21) // * "30" -> "30" // * "R" -> "30" // * "S" -> "S" -func ReplaceFinalizedCodenames(ctx PathContext, raw string) string { - num, ok := getFinalCodenamesMap(ctx.Config())[raw] +func ReplaceFinalizedCodenames(config Config, raw string) string { + num, ok := getFinalCodenamesMap(config)[raw] if !ok { return raw } @@ -197,7 +197,7 @@ func ReplaceFinalizedCodenames(ctx PathContext, raw string) string { return strconv.Itoa(num) } -// Converts the given string `raw` to an ApiLevel, possibly returning an error. +// ApiLevelFromUser converts the given string `raw` to an ApiLevel, possibly returning an error. // // `raw` must be non-empty. Passing an empty string results in a panic. // @@ -212,6 +212,12 @@ func ReplaceFinalizedCodenames(ctx PathContext, raw string) string { // Inputs that are not "current", known previews, or convertible to an integer // will return an error. func ApiLevelFromUser(ctx PathContext, raw string) (ApiLevel, error) { + return ApiLevelFromUserWithConfig(ctx.Config(), raw) +} + +// ApiLevelFromUserWithConfig implements ApiLevelFromUser, see comments for +// ApiLevelFromUser for more details. +func ApiLevelFromUserWithConfig(config Config, raw string) (ApiLevel, error) { if raw == "" { panic("API level string must be non-empty") } @@ -220,13 +226,13 @@ func ApiLevelFromUser(ctx PathContext, raw string) (ApiLevel, error) { return FutureApiLevel, nil } - for _, preview := range ctx.Config().PreviewApiLevels() { + for _, preview := range config.PreviewApiLevels() { if raw == preview.String() { return preview, nil } } - canonical := ReplaceFinalizedCodenames(ctx, raw) + canonical := ReplaceFinalizedCodenames(config, raw) asInt, err := strconv.Atoi(canonical) if err != nil { return NoneApiLevel, fmt.Errorf("%q could not be parsed as an integer and is not a recognized codename", canonical) diff --git a/android/config.go b/android/config.go index 61383e762..8e9a0a2e6 100644 --- a/android/config.go +++ b/android/config.go @@ -698,6 +698,16 @@ func (c *config) PreviewApiLevels() []ApiLevel { return levels } +func (c *config) LatestPreviewApiLevel() ApiLevel { + level := NoneApiLevel + for _, l := range c.PreviewApiLevels() { + if l.GreaterThan(level) { + level = l + } + } + return level +} + func (c *config) AllSupportedApiLevels() []ApiLevel { var levels []ApiLevel levels = append(levels, c.FinalApiLevels()...) diff --git a/android/neverallow.go b/android/neverallow.go index af072cdbb..f7827f8ef 100644 --- a/android/neverallow.go +++ b/android/neverallow.go @@ -238,7 +238,7 @@ func neverallowMutator(ctx BottomUpMutatorContext) { continue } - if !n.appliesToProperties(properties) { + if !n.appliesToProperties(ctx, properties) { continue } @@ -258,8 +258,12 @@ func neverallowMutator(ctx BottomUpMutatorContext) { } } +type ValueMatcherContext interface { + Config() Config +} + type ValueMatcher interface { - Test(string) bool + Test(ValueMatcherContext, string) bool String() string } @@ -267,7 +271,7 @@ type equalMatcher struct { expected string } -func (m *equalMatcher) Test(value string) bool { +func (m *equalMatcher) Test(ctx ValueMatcherContext, value string) bool { return m.expected == value } @@ -278,7 +282,7 @@ func (m *equalMatcher) String() string { type anyMatcher struct { } -func (m *anyMatcher) Test(value string) bool { +func (m *anyMatcher) Test(ctx ValueMatcherContext, value string) bool { return true } @@ -292,7 +296,7 @@ type startsWithMatcher struct { prefix string } -func (m *startsWithMatcher) Test(value string) bool { +func (m *startsWithMatcher) Test(ctx ValueMatcherContext, value string) bool { return strings.HasPrefix(value, m.prefix) } @@ -304,7 +308,7 @@ type regexMatcher struct { re *regexp.Regexp } -func (m *regexMatcher) Test(value string) bool { +func (m *regexMatcher) Test(ctx ValueMatcherContext, value string) bool { return m.re.MatchString(value) } @@ -316,7 +320,7 @@ type notInListMatcher struct { allowed []string } -func (m *notInListMatcher) Test(value string) bool { +func (m *notInListMatcher) Test(ctx ValueMatcherContext, value string) bool { return !InList(value, m.allowed) } @@ -326,7 +330,7 @@ func (m *notInListMatcher) String() string { type isSetMatcher struct{} -func (m *isSetMatcher) Test(value string) bool { +func (m *isSetMatcher) Test(ctx ValueMatcherContext, value string) bool { return value != "" } @@ -336,6 +340,19 @@ func (m *isSetMatcher) String() string { var isSetMatcherInstance = &isSetMatcher{} +type sdkVersionMatcher struct { + condition func(ctx ValueMatcherContext, spec SdkSpec) bool + description string +} + +func (m *sdkVersionMatcher) Test(ctx ValueMatcherContext, value string) bool { + return m.condition(ctx, SdkSpecFromWithConfig(ctx.Config(), value)) +} + +func (m *sdkVersionMatcher) String() string { + return ".sdk-version(" + m.description + ")" +} + type ruleProperty struct { fields []string // e.x.: Vndk.Enabled matcher ValueMatcher @@ -549,9 +566,10 @@ func (r *rule) appliesToModuleType(moduleType string) bool { return (len(r.moduleTypes) == 0 || InList(moduleType, r.moduleTypes)) && !InList(moduleType, r.unlessModuleTypes) } -func (r *rule) appliesToProperties(properties []interface{}) bool { - includeProps := hasAllProperties(properties, r.props) - excludeProps := hasAnyProperty(properties, r.unlessProps) +func (r *rule) appliesToProperties(ctx ValueMatcherContext, + properties []interface{}) bool { + includeProps := hasAllProperties(ctx, properties, r.props) + excludeProps := hasAnyProperty(ctx, properties, r.unlessProps) return includeProps && !excludeProps } @@ -571,6 +589,16 @@ func NotInList(allowed []string) ValueMatcher { return ¬InListMatcher{allowed} } +func LessThanSdkVersion(sdk string) ValueMatcher { + return &sdkVersionMatcher{ + condition: func(ctx ValueMatcherContext, spec SdkSpec) bool { + return spec.ApiLevel.LessThan( + SdkSpecFromWithConfig(ctx.Config(), sdk).ApiLevel) + }, + description: "lessThan=" + sdk, + } +} + // assorted utils func cleanPaths(paths []string) []string { @@ -589,25 +617,28 @@ func fieldNamesForProperties(propertyNames string) []string { return names } -func hasAnyProperty(properties []interface{}, props []ruleProperty) bool { +func hasAnyProperty(ctx ValueMatcherContext, properties []interface{}, + props []ruleProperty) bool { for _, v := range props { - if hasProperty(properties, v) { + if hasProperty(ctx, properties, v) { return true } } return false } -func hasAllProperties(properties []interface{}, props []ruleProperty) bool { +func hasAllProperties(ctx ValueMatcherContext, properties []interface{}, + props []ruleProperty) bool { for _, v := range props { - if !hasProperty(properties, v) { + if !hasProperty(ctx, properties, v) { return false } } return true } -func hasProperty(properties []interface{}, prop ruleProperty) bool { +func hasProperty(ctx ValueMatcherContext, properties []interface{}, + prop ruleProperty) bool { for _, propertyStruct := range properties { propertiesValue := reflect.ValueOf(propertyStruct).Elem() for _, v := range prop.fields { @@ -621,7 +652,7 @@ func hasProperty(properties []interface{}, prop ruleProperty) bool { } check := func(value string) bool { - return prop.matcher.Test(value) + return prop.matcher.Test(ctx, value) } if matchValue(propertiesValue, check) { diff --git a/android/neverallow_test.go b/android/neverallow_test.go index 35aadd8b8..0b93fcfd7 100644 --- a/android/neverallow_test.go +++ b/android/neverallow_test.go @@ -296,6 +296,48 @@ var neverallowTests = []struct { "Only boot images may be imported as a makefile goal.", }, }, + { + name: "min_sdk too low", + fs: map[string][]byte{ + "Android.bp": []byte(` + java_library { + name: "min_sdk_too_low", + min_sdk_version: "30", + }`), + }, + rules: []Rule{ + NeverAllow().WithMatcher("min_sdk_version", LessThanSdkVersion("31")), + }, + expectedErrors: []string{ + "module \"min_sdk_too_low\": violates neverallow", + }, + }, + { + name: "min_sdk high enough", + fs: map[string][]byte{ + "Android.bp": []byte(` + java_library { + name: "min_sdk_high_enough", + min_sdk_version: "31", + }`), + }, + rules: []Rule{ + NeverAllow().WithMatcher("min_sdk_version", LessThanSdkVersion("31")), + }, + }, + { + name: "current min_sdk high enough", + fs: map[string][]byte{ + "Android.bp": []byte(` + java_library { + name: "current_min_sdk_high_enough", + min_sdk_version: "current", + }`), + }, + rules: []Rule{ + NeverAllow().WithMatcher("min_sdk_version", LessThanSdkVersion("31")), + }, + }, } var prepareForNeverAllowTest = GroupFixturePreparers( @@ -379,9 +421,10 @@ func (p *mockCcLibraryModule) GenerateAndroidBuildActions(ModuleContext) { } type mockJavaLibraryProperties struct { - Libs []string - Sdk_version *string - Uncompress_dex *bool + Libs []string + Min_sdk_version *string + Sdk_version *string + Uncompress_dex *bool } type mockJavaLibraryModule struct { diff --git a/android/sdk_version.go b/android/sdk_version.go index c6c75a399..49e607502 100644 --- a/android/sdk_version.go +++ b/android/sdk_version.go @@ -117,7 +117,7 @@ func (s SdkSpec) Stable() bool { return false } -// PrebuiltSdkAvailableForUnbundledBuilt tells whether this SdkSpec can have a prebuilt SDK +// PrebuiltSdkAvailableForUnbundledBuild tells whether this SdkSpec can have a prebuilt SDK // that can be used for unbundled builds. func (s SdkSpec) PrebuiltSdkAvailableForUnbundledBuild() bool { // "", "none", and "core_platform" are not available for unbundled build @@ -212,6 +212,10 @@ var ( ) func SdkSpecFrom(ctx EarlyModuleContext, str string) SdkSpec { + return SdkSpecFromWithConfig(ctx.Config(), str) +} + +func SdkSpecFromWithConfig(config Config, str string) SdkSpec { switch str { // special cases first case "": @@ -252,7 +256,7 @@ func SdkSpecFrom(ctx EarlyModuleContext, str string) SdkSpec { return SdkSpec{SdkInvalid, NoneApiLevel, str} } - apiLevel, err := ApiLevelFromUser(ctx, versionString) + apiLevel, err := ApiLevelFromUserWithConfig(config, versionString) if err != nil { return SdkSpec{SdkInvalid, apiLevel, str} } diff --git a/android/sdk_version_test.go b/android/sdk_version_test.go new file mode 100644 index 000000000..8924fd295 --- /dev/null +++ b/android/sdk_version_test.go @@ -0,0 +1,89 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package android + +import ( + "testing" +) + +func TestSdkSpecFrom(t *testing.T) { + testCases := []struct { + input string + expected string + }{ + { + input: "", + expected: "private_current", + }, + { + input: "none", + expected: "none_(no version)", + }, + { + input: "core_platform", + expected: "core_platform_current", + }, + { + input: "_", + expected: "invalid_(no version)", + }, + { + input: "_31", + expected: "invalid_(no version)", + }, + { + input: "system_R", + expected: "system_30", + }, + { + input: "test_31", + expected: "test_31", + }, + { + input: "module_current", + expected: "module-lib_current", + }, + { + input: "31", + expected: "public_31", + }, + { + input: "S", + expected: "public_31", + }, + { + input: "current", + expected: "public_current", + }, + { + input: "Tiramisu", + expected: "public_Tiramisu", + }, + } + + config := NullConfig("") + + config.productVariables = productVariables{ + Platform_sdk_version: intPtr(31), + Platform_sdk_codename: stringPtr("Tiramisu"), + Platform_version_active_codenames: []string{"Tiramisu"}, + } + + for _, tc := range testCases { + if got := SdkSpecFromWithConfig(config, tc.input).String(); tc.expected != got { + t.Errorf("Expected %v, got %v", tc.expected, got) + } + } +} diff --git a/apex/androidmk.go b/apex/androidmk.go index ebf08330b..6695a6fea 100644 --- a/apex/androidmk.go +++ b/apex/androidmk.go @@ -446,23 +446,18 @@ func (a *apexBundle) androidMkForType() android.AndroidMkData { fmt.Fprintf(w, dist) } - if a.apisUsedByModuleFile.String() != "" { - goal := "apps_only" - distFile := a.apisUsedByModuleFile.String() - fmt.Fprintf(w, "ifneq (,$(filter $(my_register_name),$(TARGET_BUILD_APPS)))\n"+ - " $(call dist-for-goals,%s,%s:ndk_apis_usedby_apex/$(notdir %s))\n"+ - "endif\n", - goal, distFile, distFile) - } - - if a.apisBackedByModuleFile.String() != "" { - goal := "apps_only" - distFile := a.apisBackedByModuleFile.String() - fmt.Fprintf(w, "ifneq (,$(filter $(my_register_name),$(TARGET_BUILD_APPS)))\n"+ - " $(call dist-for-goals,%s,%s:ndk_apis_backedby_apex/$(notdir %s))\n"+ - "endif\n", - goal, distFile, distFile) - } + distCoverageFiles(w, "ndk_apis_usedby_apex", a.nativeApisUsedByModuleFile.String()) + distCoverageFiles(w, "ndk_apis_backedby_apex", a.nativeApisBackedByModuleFile.String()) + distCoverageFiles(w, "java_apis_used_by_apex", a.javaApisUsedByModuleFile.String()) } }} } + +func distCoverageFiles(w io.Writer, dir string, distfile string) { + if distfile != "" { + goal := "apps_only" + fmt.Fprintf(w, "ifneq (,$(filter $(my_register_name),$(TARGET_BUILD_APPS)))\n"+ + " $(call dist-for-goals,%s,%s:%s/$(notdir %s))\n"+ + "endif\n", goal, distfile, dir, distfile) + } +} diff --git a/apex/apex.go b/apex/apex.go index a2b16f151..e1bc030c5 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -95,6 +95,14 @@ type apexBundleProperties struct { // /system/sepolicy/apex/<module_name>_file_contexts. File_contexts *string `android:"path"` + // Path to the canned fs config file for customizing file's uid/gid/mod/capabilities. The + // format is /<path_or_glob> <uid> <gid> <mode> [capabilities=0x<cap>], where path_or_glob is a + // path or glob pattern for a file or set of files, uid/gid are numerial values of user ID + // and group ID, mode is octal value for the file mode, and cap is hexadecimal value for the + // capability. If this property is not set, or a file is missing in the file, default config + // is used. + Canned_fs_config *string `android:"path"` + ApexNativeDependencies Multilib apexMultilibProperties @@ -413,8 +421,9 @@ type apexBundle struct { isCompressed bool // Path of API coverage generate file - apisUsedByModuleFile android.ModuleOutPath - apisBackedByModuleFile android.ModuleOutPath + nativeApisUsedByModuleFile android.ModuleOutPath + nativeApisBackedByModuleFile android.ModuleOutPath + javaApisUsedByModuleFile android.ModuleOutPath } // apexFileClass represents a type of file that can be included in APEX. @@ -1563,8 +1572,8 @@ func apexFileForRuntimeResourceOverlay(ctx android.BaseModuleContext, rro java.R return af } -func apexFileForBpfProgram(ctx android.BaseModuleContext, builtFile android.Path, bpfProgram bpf.BpfModule) apexFile { - dirInApex := filepath.Join("etc", "bpf") +func apexFileForBpfProgram(ctx android.BaseModuleContext, builtFile android.Path, apex_sub_dir string, bpfProgram bpf.BpfModule) apexFile { + dirInApex := filepath.Join("etc", "bpf", apex_sub_dir) return newApexFile(ctx, builtFile, builtFile.Base(), dirInApex, etc, bpfProgram) } @@ -1631,7 +1640,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { // 1) do some validity checks such as apex_available, min_sdk_version, etc. a.checkApexAvailability(ctx) a.checkUpdatable(ctx) - a.checkMinSdkVersion(ctx) + a.CheckMinSdkVersion(ctx) a.checkStaticLinkingToStubLibraries(ctx) if len(a.properties.Tests) > 0 && !a.testApex { ctx.PropertyErrorf("tests", "property allowed only in apex_test module type") @@ -1763,8 +1772,9 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { case bpfTag: if bpfProgram, ok := child.(bpf.BpfModule); ok { filesToCopy, _ := bpfProgram.OutputFiles("") + apex_sub_dir := bpfProgram.SubDir() for _, bpfFile := range filesToCopy { - filesInfo = append(filesInfo, apexFileForBpfProgram(ctx, bpfFile, bpfProgram)) + filesInfo = append(filesInfo, apexFileForBpfProgram(ctx, bpfFile, apex_sub_dir, bpfProgram)) } } else { ctx.PropertyErrorf("bpfs", "%q is not a bpf module", depName) @@ -2245,18 +2255,28 @@ func overrideApexFactory() android.Module { // // TODO(jiyong): move these checks to a separate go file. +var _ android.ModuleWithMinSdkVersionCheck = (*apexBundle)(nil) + // Entures that min_sdk_version of the included modules are equal or less than the min_sdk_version // of this apexBundle. -func (a *apexBundle) checkMinSdkVersion(ctx android.ModuleContext) { +func (a *apexBundle) CheckMinSdkVersion(ctx android.ModuleContext) { if a.testApex || a.vndkApex { return } // apexBundle::minSdkVersion reports its own errors. minSdkVersion := a.minSdkVersion(ctx) - android.CheckMinSdkVersion(a, ctx, minSdkVersion) + android.CheckMinSdkVersion(ctx, minSdkVersion, a.WalkPayloadDeps) } -func (a *apexBundle) minSdkVersion(ctx android.BaseModuleContext) android.ApiLevel { +func (a *apexBundle) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { + return android.SdkSpec{ + Kind: android.SdkNone, + ApiLevel: a.minSdkVersion(ctx), + Raw: String(a.properties.Min_sdk_version), + } +} + +func (a *apexBundle) minSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel { ver := proptools.String(a.properties.Min_sdk_version) if ver == "" { return android.NoneApiLevel @@ -2328,6 +2348,12 @@ func (a *apexBundle) checkUpdatable(ctx android.ModuleContext) { func (a *apexBundle) checkClasspathFragments(ctx android.ModuleContext) { ctx.VisitDirectDeps(func(module android.Module) { if tag := ctx.OtherModuleDependencyTag(module); tag == bcpfTag || tag == sscpfTag { + if tag == sscpfTag { + sscpf := module.(*java.SystemServerClasspathModule) + if sscpf.ShouldIgnore() { + return + } + } info := ctx.OtherModuleProvider(module, java.ClasspathFragmentProtoContentInfoProvider).(java.ClasspathFragmentProtoContentInfo) if !info.ClasspathFragmentProtoGenerated { ctx.OtherModuleErrorf(module, "is included in updatable apex %v, it must not set generate_classpaths_proto to false", ctx.ModuleName()) @@ -3038,15 +3064,16 @@ func createApexPermittedPackagesRules(modules_packages map[string][]string) []an BootclasspathJar(). With("apex_available", module_name). WithMatcher("permitted_packages", android.NotInList(module_packages)). + WithMatcher("min_sdk_version", android.LessThanSdkVersion("Tiramisu")). Because("jars that are part of the " + module_name + " module may only allow these packages: " + strings.Join(module_packages, ",") + - ". Please jarjar or move code around.") + " with min_sdk < T. Please jarjar or move code around.") rules = append(rules, permittedPackagesRule) } return rules } -// DO NOT EDIT! These are the package prefixes that are exempted from being AOT'ed by ART. +// DO NOT EDIT! These are the package prefixes that are exempted from being AOT'ed by ART on Q/R/S. // Adding code to the bootclasspath in new packages will cause issues on module update. func qModulesPackages() map[string][]string { return map[string][]string{ @@ -3060,7 +3087,7 @@ func qModulesPackages() map[string][]string { } } -// DO NOT EDIT! These are the package prefixes that are exempted from being AOT'ed by ART. +// DO NOT EDIT! These are the package prefixes that are exempted from being AOT'ed by ART on R/S. // Adding code to the bootclasspath in new packages will cause issues on module update. func rModulesPackages() map[string][]string { return map[string][]string{ diff --git a/apex/apex_test.go b/apex/apex_test.go index 12317a275..f3c3b44c5 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -622,7 +622,7 @@ func TestDefaults(t *testing.T) { java_libs: ["myjar"], apps: ["AppFoo"], rros: ["rro"], - bpfs: ["bpf"], + bpfs: ["bpf", "netd_test"], updatable: false, } @@ -675,6 +675,12 @@ func TestDefaults(t *testing.T) { srcs: ["bpf.c", "bpf2.c"], } + bpf { + name: "netd_test", + srcs: ["netd_test.c"], + sub_dir: "netd", + } + `) ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ "etc/myetc", @@ -684,6 +690,7 @@ func TestDefaults(t *testing.T) { "overlay/blue/rro.apk", "etc/bpf/bpf.o", "etc/bpf/bpf2.o", + "etc/bpf/netd/netd_test.o", }) } @@ -2293,22 +2300,21 @@ func TestFilesInSubDir(t *testing.T) { `) generateFsRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("generateFsConfig") - dirs := strings.Split(generateFsRule.Args["exec_paths"], " ") + cmd := generateFsRule.RuleParams.Command // Ensure that the subdirectories are all listed - ensureListContains(t, dirs, "etc") - ensureListContains(t, dirs, "etc/foo") - ensureListContains(t, dirs, "etc/foo/bar") - ensureListContains(t, dirs, "lib64") - ensureListContains(t, dirs, "lib64/foo") - ensureListContains(t, dirs, "lib64/foo/bar") - ensureListContains(t, dirs, "lib") - ensureListContains(t, dirs, "lib/foo") - ensureListContains(t, dirs, "lib/foo/bar") - - ensureListContains(t, dirs, "bin") - ensureListContains(t, dirs, "bin/foo") - ensureListContains(t, dirs, "bin/foo/bar") + ensureContains(t, cmd, "/etc ") + ensureContains(t, cmd, "/etc/foo ") + ensureContains(t, cmd, "/etc/foo/bar ") + ensureContains(t, cmd, "/lib64 ") + ensureContains(t, cmd, "/lib64/foo ") + ensureContains(t, cmd, "/lib64/foo/bar ") + ensureContains(t, cmd, "/lib ") + ensureContains(t, cmd, "/lib/foo ") + ensureContains(t, cmd, "/lib/foo/bar ") + ensureContains(t, cmd, "/bin ") + ensureContains(t, cmd, "/bin/foo ") + ensureContains(t, cmd, "/bin/foo/bar ") } func TestFilesInSubDirWhenNativeBridgeEnabled(t *testing.T) { @@ -6897,6 +6903,7 @@ func TestApexPermittedPackagesRules(t *testing.T) { apex_available: ["myapex"], sdk_version: "none", system_modules: "none", + min_sdk_version: "30", } java_library { name: "nonbcp_lib2", @@ -6905,9 +6912,11 @@ func TestApexPermittedPackagesRules(t *testing.T) { permitted_packages: ["a.b"], sdk_version: "none", system_modules: "none", + min_sdk_version: "30", } apex { name: "myapex", + min_sdk_version: "30", key: "myapex.key", java_libs: ["bcp_lib1", "nonbcp_lib2"], updatable: false, @@ -6920,8 +6929,45 @@ func TestApexPermittedPackagesRules(t *testing.T) { }, }, { - name: "Bootclasspath apex jar not satisfying allowed module packages.", - expectedError: `module "bcp_lib2" .* which is restricted because jars that are part of the myapex module may only allow these packages: foo.bar. Please jarjar or move code around.`, + name: "Bootclasspath apex jar not satisfying allowed module packages on Q.", + expectedError: `module "bcp_lib2" .* which is restricted because jars that are part of the myapex module may only allow these packages: foo.bar with min_sdk < T. Please jarjar or move code around.`, + bp: ` + java_library { + name: "bcp_lib1", + srcs: ["lib1/src/*.java"], + apex_available: ["myapex"], + permitted_packages: ["foo.bar"], + sdk_version: "none", + system_modules: "none", + min_sdk_version: "29", + } + java_library { + name: "bcp_lib2", + srcs: ["lib2/src/*.java"], + apex_available: ["myapex"], + permitted_packages: ["foo.bar", "bar.baz"], + sdk_version: "none", + system_modules: "none", + min_sdk_version: "29", + } + apex { + name: "myapex", + min_sdk_version: "29", + key: "myapex.key", + java_libs: ["bcp_lib1", "bcp_lib2"], + updatable: false, + } + `, + bootJars: []string{"bcp_lib1", "bcp_lib2"}, + modulesPackages: map[string][]string{ + "myapex": []string{ + "foo.bar", + }, + }, + }, + { + name: "Bootclasspath apex jar not satisfying allowed module packages on R.", + expectedError: `module "bcp_lib2" .* which is restricted because jars that are part of the myapex module may only allow these packages: foo.bar with min_sdk < T. Please jarjar or move code around.`, bp: ` java_library { name: "bcp_lib1", @@ -6930,6 +6976,7 @@ func TestApexPermittedPackagesRules(t *testing.T) { permitted_packages: ["foo.bar"], sdk_version: "none", system_modules: "none", + min_sdk_version: "30", } java_library { name: "bcp_lib2", @@ -6938,9 +6985,48 @@ func TestApexPermittedPackagesRules(t *testing.T) { permitted_packages: ["foo.bar", "bar.baz"], sdk_version: "none", system_modules: "none", + min_sdk_version: "30", } apex { name: "myapex", + min_sdk_version: "30", + key: "myapex.key", + java_libs: ["bcp_lib1", "bcp_lib2"], + updatable: false, + } + `, + bootJars: []string{"bcp_lib1", "bcp_lib2"}, + modulesPackages: map[string][]string{ + "myapex": []string{ + "foo.bar", + }, + }, + }, + { + name: "Bootclasspath apex jar >= T not satisfying Q/R/S allowed module packages.", + expectedError: "", + bp: ` + java_library { + name: "bcp_lib1", + srcs: ["lib1/src/*.java"], + apex_available: ["myapex"], + permitted_packages: ["foo.bar"], + sdk_version: "none", + system_modules: "none", + min_sdk_version: "current", + } + java_library { + name: "bcp_lib2", + srcs: ["lib2/src/*.java"], + apex_available: ["myapex"], + permitted_packages: ["foo.bar", "bar.baz"], + sdk_version: "none", + system_modules: "none", + min_sdk_version: "current", + } + apex { + name: "myapex", + min_sdk_version: "current", key: "myapex.key", java_libs: ["bcp_lib1", "bcp_lib2"], updatable: false, @@ -7742,6 +7828,184 @@ func TestApexJavaCoverage(t *testing.T) { } } +func TestSdkLibraryCanHaveHigherMinSdkVersion(t *testing.T) { + preparer := android.GroupFixturePreparers( + PrepareForTestWithApexBuildComponents, + prepareForTestWithMyapex, + java.PrepareForTestWithJavaSdkLibraryFiles, + java.PrepareForTestWithJavaDefaultModules, + android.PrepareForTestWithAndroidBuildComponents, + dexpreopt.FixtureSetApexBootJars("myapex:mybootclasspathlib"), + dexpreopt.FixtureSetApexSystemServerJars("myapex:mysystemserverclasspathlib"), + ) + + // Test java_sdk_library in bootclasspath_fragment may define higher min_sdk_version than the apex + t.Run("bootclasspath_fragment jar has higher min_sdk_version than apex", func(t *testing.T) { + preparer.RunTestWithBp(t, ` + apex { + name: "myapex", + key: "myapex.key", + bootclasspath_fragments: ["mybootclasspathfragment"], + min_sdk_version: "30", + updatable: false, + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + bootclasspath_fragment { + name: "mybootclasspathfragment", + contents: ["mybootclasspathlib"], + apex_available: ["myapex"], + } + + java_sdk_library { + name: "mybootclasspathlib", + srcs: ["mybootclasspathlib.java"], + apex_available: ["myapex"], + compile_dex: true, + unsafe_ignore_missing_latest_api: true, + min_sdk_version: "31", + static_libs: ["util"], + } + + java_library { + name: "util", + srcs: ["a.java"], + apex_available: ["myapex"], + min_sdk_version: "31", + static_libs: ["another_util"], + } + + java_library { + name: "another_util", + srcs: ["a.java"], + min_sdk_version: "31", + apex_available: ["myapex"], + } + `) + }) + + // Test java_sdk_library in systemserverclasspath_fragment may define higher min_sdk_version than the apex + t.Run("systemserverclasspath_fragment jar has higher min_sdk_version than apex", func(t *testing.T) { + preparer.RunTestWithBp(t, ` + apex { + name: "myapex", + key: "myapex.key", + systemserverclasspath_fragments: ["mysystemserverclasspathfragment"], + min_sdk_version: "30", + updatable: false, + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + systemserverclasspath_fragment { + name: "mysystemserverclasspathfragment", + contents: ["mysystemserverclasspathlib"], + apex_available: ["myapex"], + } + + java_sdk_library { + name: "mysystemserverclasspathlib", + srcs: ["mysystemserverclasspathlib.java"], + apex_available: ["myapex"], + compile_dex: true, + min_sdk_version: "32", + unsafe_ignore_missing_latest_api: true, + static_libs: ["util"], + } + + java_library { + name: "util", + srcs: ["a.java"], + apex_available: ["myapex"], + min_sdk_version: "31", + static_libs: ["another_util"], + } + + java_library { + name: "another_util", + srcs: ["a.java"], + min_sdk_version: "31", + apex_available: ["myapex"], + } + `) + }) + + t.Run("bootclasspath_fragment jar must set min_sdk_version", func(t *testing.T) { + preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "mybootclasspathlib".*must set min_sdk_version`)). + RunTestWithBp(t, ` + apex { + name: "myapex", + key: "myapex.key", + bootclasspath_fragments: ["mybootclasspathfragment"], + min_sdk_version: "30", + updatable: false, + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + bootclasspath_fragment { + name: "mybootclasspathfragment", + contents: ["mybootclasspathlib"], + apex_available: ["myapex"], + } + + java_sdk_library { + name: "mybootclasspathlib", + srcs: ["mybootclasspathlib.java"], + apex_available: ["myapex"], + compile_dex: true, + unsafe_ignore_missing_latest_api: true, + } + `) + }) + + t.Run("systemserverclasspath_fragment jar must set min_sdk_version", func(t *testing.T) { + preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "mysystemserverclasspathlib".*must set min_sdk_version`)). + RunTestWithBp(t, ` + apex { + name: "myapex", + key: "myapex.key", + systemserverclasspath_fragments: ["mysystemserverclasspathfragment"], + min_sdk_version: "30", + updatable: false, + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + systemserverclasspath_fragment { + name: "mysystemserverclasspathfragment", + contents: ["mysystemserverclasspathlib"], + apex_available: ["myapex"], + } + + java_sdk_library { + name: "mysystemserverclasspathlib", + srcs: ["mysystemserverclasspathlib.java"], + apex_available: ["myapex"], + compile_dex: true, + unsafe_ignore_missing_latest_api: true, + } + `) + }) +} + func TestMain(m *testing.M) { os.Exit(m.Run()) } diff --git a/apex/builder.go b/apex/builder.go index d2e6ad8d5..8a94ad7c7 100644 --- a/apex/builder.go +++ b/apex/builder.go @@ -67,23 +67,11 @@ func init() { pctx.HostBinToolVariable("make_f2fs", "make_f2fs") pctx.HostBinToolVariable("sload_f2fs", "sload_f2fs") pctx.HostBinToolVariable("apex_compression_tool", "apex_compression_tool") + pctx.HostBinToolVariable("dexdeps", "dexdeps") pctx.SourcePathVariable("genNdkUsedbyApexPath", "build/soong/scripts/gen_ndk_usedby_apex.sh") } var ( - // Create a canned fs config file where all files and directories are - // by default set to (uid/gid/mode) = (1000/1000/0644) - // TODO(b/113082813) make this configurable using config.fs syntax - generateFsConfig = pctx.StaticRule("generateFsConfig", blueprint.RuleParams{ - Command: `( echo '/ 1000 1000 0755' ` + - `&& for i in ${ro_paths}; do echo "/$$i 1000 1000 0644"; done ` + - `&& for i in ${exec_paths}; do echo "/$$i 0 2000 0755"; done ` + - `&& ( tr ' ' '\n' <${out}.apklist | for i in ${apk_paths}; do read apk; echo "/$$i 0 2000 0755"; zipinfo -1 $$apk | sed "s:\(.*\):/$$i/\1 1000 1000 0644:"; done ) ) > ${out}`, - Description: "fs_config ${out}", - Rspfile: "$out.apklist", - RspfileContent: "$in", - }, "ro_paths", "exec_paths", "apk_paths") - apexManifestRule = pctx.StaticRule("apexManifestRule", blueprint.RuleParams{ Command: `rm -f $out && ${jsonmodify} $in ` + `-a provideNativeLibs ${provideNativeLibs} ` + @@ -520,55 +508,11 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { // Figure out if need to compress apex. compressionEnabled := ctx.Config().CompressedApex() && proptools.BoolDefault(a.properties.Compressible, false) && !a.testApex && !ctx.Config().UnbundledBuildApps() if apexType == imageApex { + //////////////////////////////////////////////////////////////////////////////////// // Step 2: create canned_fs_config which encodes filemode,uid,gid of each files // in this APEX. The file will be used by apexer in later steps. - // TODO(jiyong): make this as a function - // TODO(jiyong): use the RuleBuilder - var readOnlyPaths = []string{"apex_manifest.json", "apex_manifest.pb"} - var executablePaths []string // this also includes dirs - var extractedAppSetPaths android.Paths - var extractedAppSetDirs []string - for _, f := range a.filesInfo { - pathInApex := f.path() - if f.installDir == "bin" || strings.HasPrefix(f.installDir, "bin/") { - executablePaths = append(executablePaths, pathInApex) - for _, d := range f.dataPaths { - readOnlyPaths = append(readOnlyPaths, filepath.Join(f.installDir, d.RelativeInstallPath, d.SrcPath.Rel())) - } - for _, s := range f.symlinks { - executablePaths = append(executablePaths, filepath.Join(f.installDir, s)) - } - } else if f.class == appSet { - extractedAppSetPaths = append(extractedAppSetPaths, f.builtFile) - extractedAppSetDirs = append(extractedAppSetDirs, f.installDir) - } else { - readOnlyPaths = append(readOnlyPaths, pathInApex) - } - dir := f.installDir - for !android.InList(dir, executablePaths) && dir != "" { - executablePaths = append(executablePaths, dir) - dir, _ = filepath.Split(dir) // move up to the parent - if len(dir) > 0 { - // remove trailing slash - dir = dir[:len(dir)-1] - } - } - } - sort.Strings(readOnlyPaths) - sort.Strings(executablePaths) - cannedFsConfig := android.PathForModuleOut(ctx, "canned_fs_config") - ctx.Build(pctx, android.BuildParams{ - Rule: generateFsConfig, - Output: cannedFsConfig, - Description: "generate fs config", - Inputs: extractedAppSetPaths, - Args: map[string]string{ - "ro_paths": strings.Join(readOnlyPaths, " "), - "exec_paths": strings.Join(executablePaths, " "), - "apk_paths": strings.Join(extractedAppSetDirs, " "), - }, - }) + cannedFsConfig := a.buildCannedFsConfig(ctx) implicitInputs = append(implicitInputs, cannedFsConfig) //////////////////////////////////////////////////////////////////////////////////// @@ -696,12 +640,12 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { "readelf": "${config.ClangBin}/llvm-readelf", }, }) - a.apisUsedByModuleFile = apisUsedbyOutputFile + a.nativeApisUsedByModuleFile = apisUsedbyOutputFile - var libNames []string + var nativeLibNames []string for _, f := range a.filesInfo { if f.class == nativeSharedLib { - libNames = append(libNames, f.stem()) + nativeLibNames = append(nativeLibNames, f.stem()) } } apisBackedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_backing.txt") @@ -711,9 +655,25 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { Tool(android.PathForSource(ctx, "build/soong/scripts/gen_ndk_backedby_apex.sh")). Output(apisBackedbyOutputFile). Input(ndkLibraryList). - Flags(libNames) + Flags(nativeLibNames) rule.Build("ndk_backedby_list", "Generate API libraries backed by Apex") - a.apisBackedByModuleFile = apisBackedbyOutputFile + a.nativeApisBackedByModuleFile = apisBackedbyOutputFile + + var javaLibOrApkPath []android.Path + for _, f := range a.filesInfo { + if f.class == javaSharedLib || f.class == app { + javaLibOrApkPath = append(javaLibOrApkPath, f.builtFile) + } + } + javaApiUsedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_using.xml") + javaUsedByRule := android.NewRuleBuilder(pctx, ctx) + javaUsedByRule.Command(). + Tool(android.PathForSource(ctx, "build/soong/scripts/gen_java_usedby_apex.sh")). + BuiltTool("dexdeps"). + Output(javaApiUsedbyOutputFile). + Inputs(javaLibOrApkPath) + javaUsedByRule.Build("java_usedby_list", "Generate Java APIs used by Apex") + a.javaApisUsedByModuleFile = javaApiUsedbyOutputFile bundleConfig := a.buildBundleConfig(ctx) @@ -988,3 +948,65 @@ func (a *apexBundle) buildLintReports(ctx android.ModuleContext) { a.lintReports = java.BuildModuleLintReportZips(ctx, depSetsBuilder.Build()) } + +func (a *apexBundle) buildCannedFsConfig(ctx android.ModuleContext) android.OutputPath { + var readOnlyPaths = []string{"apex_manifest.json", "apex_manifest.pb"} + var executablePaths []string // this also includes dirs + var appSetDirs []string + appSetFiles := make(map[string]android.Path) + for _, f := range a.filesInfo { + pathInApex := f.path() + if f.installDir == "bin" || strings.HasPrefix(f.installDir, "bin/") { + executablePaths = append(executablePaths, pathInApex) + for _, d := range f.dataPaths { + readOnlyPaths = append(readOnlyPaths, filepath.Join(f.installDir, d.RelativeInstallPath, d.SrcPath.Rel())) + } + for _, s := range f.symlinks { + executablePaths = append(executablePaths, filepath.Join(f.installDir, s)) + } + } else if f.class == appSet { + appSetDirs = append(appSetDirs, f.installDir) + appSetFiles[f.installDir] = f.builtFile + } else { + readOnlyPaths = append(readOnlyPaths, pathInApex) + } + dir := f.installDir + for !android.InList(dir, executablePaths) && dir != "" { + executablePaths = append(executablePaths, dir) + dir, _ = filepath.Split(dir) // move up to the parent + if len(dir) > 0 { + // remove trailing slash + dir = dir[:len(dir)-1] + } + } + } + sort.Strings(readOnlyPaths) + sort.Strings(executablePaths) + sort.Strings(appSetDirs) + + cannedFsConfig := android.PathForModuleOut(ctx, "canned_fs_config") + builder := android.NewRuleBuilder(pctx, ctx) + cmd := builder.Command() + cmd.Text("(") + cmd.Text("echo '/ 1000 1000 0755';") + for _, p := range readOnlyPaths { + cmd.Textf("echo '/%s 1000 1000 0644';", p) + } + for _, p := range executablePaths { + cmd.Textf("echo '/%s 0 2000 0755';", p) + } + for _, dir := range appSetDirs { + cmd.Textf("echo '/%s 0 2000 0755';", dir) + file := appSetFiles[dir] + cmd.Text("zipinfo -1").Input(file).Textf(`| sed "s:\(.*\):/%s/\1 1000 1000 0644:";`, dir) + } + // Custom fs_config is "appended" to the last so that entries from the file are preferred + // over default ones set above. + if a.properties.Canned_fs_config != nil { + cmd.Text("cat").Input(android.PathForModuleSrc(ctx, *a.properties.Canned_fs_config)) + } + cmd.Text(")").FlagWithOutput("> ", cannedFsConfig) + builder.Build("generateFsConfig", fmt.Sprintf("Generating canned fs config for %s", a.BaseModuleName())) + + return cannedFsConfig.OutputPath +} diff --git a/apex/testing.go b/apex/testing.go index 69bd73e5d..337c86210 100644 --- a/apex/testing.go +++ b/apex/testing.go @@ -24,6 +24,7 @@ var PrepareForTestWithApexBuildComponents = android.GroupFixturePreparers( android.MockFS{ // Needed by apex. "system/core/rootdir/etc/public.libraries.android.txt": nil, + "build/soong/scripts/gen_java_usedby_apex.sh": nil, "build/soong/scripts/gen_ndk_backedby_apex.sh": nil, // Needed by prebuilt_apex. "build/soong/scripts/unpack-prebuilt-apex.sh": nil, diff --git a/bpf/bpf.go b/bpf/bpf.go index fa1a84d04..187b4db61 100644 --- a/bpf/bpf.go +++ b/bpf/bpf.go @@ -54,12 +54,16 @@ type BpfModule interface { android.Module OutputFiles(tag string) (android.Paths, error) + + // Returns the sub install directory if the bpf module is included by apex. + SubDir() string } type BpfProperties struct { Srcs []string `android:"path"` Cflags []string Include_dirs []string + Sub_dir string } type bpf struct { @@ -83,9 +87,9 @@ func (bpf *bpf) GenerateAndroidBuildActions(ctx android.ModuleContext) { // The architecture doesn't matter here, but asm/types.h is included by linux/types.h. "-isystem bionic/libc/kernel/uapi/asm-arm64", "-isystem bionic/libc/kernel/android/uapi", + "-I frameworks/libs/net/common/native/bpf_headers/include/bpf", // TODO(b/149785767): only give access to specific file with AID_* constants "-I system/core/libcutils/include", - "-I system/bpf/progs/include", "-I " + ctx.ModuleDir(), } @@ -121,6 +125,10 @@ func (bpf *bpf) AndroidMk() android.AndroidMkData { fmt.Fprintln(w) fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir) fmt.Fprintln(w) + localModulePath := "LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/bpf" + if len(bpf.properties.Sub_dir) > 0 { + localModulePath += "/" + bpf.properties.Sub_dir + } for _, obj := range bpf.objs { objName := name + "_" + obj.Base() names = append(names, objName) @@ -130,7 +138,7 @@ func (bpf *bpf) AndroidMk() android.AndroidMkData { fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", obj.String()) fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", obj.Base()) fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC") - fmt.Fprintln(w, "LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/bpf") + fmt.Fprintln(w, localModulePath) fmt.Fprintln(w, "include $(BUILD_PREBUILT)") fmt.Fprintln(w) } @@ -154,6 +162,10 @@ func (bpf *bpf) OutputFiles(tag string) (android.Paths, error) { } } +func (bpf *bpf) SubDir() string { + return bpf.properties.Sub_dir +} + var _ android.OutputFileProducer = (*bpf)(nil) func BpfFactory() android.Module { diff --git a/dexpreopt/testing.go b/dexpreopt/testing.go index 2f996555f..63d5317c5 100644 --- a/dexpreopt/testing.go +++ b/dexpreopt/testing.go @@ -122,6 +122,14 @@ func FixtureSetBootJars(bootJars ...string) android.FixturePreparer { func FixtureSetApexBootJars(bootJars ...string) android.FixturePreparer { return FixtureModifyGlobalConfig(func(dexpreoptConfig *GlobalConfig) { dexpreoptConfig.ApexBootJars = android.CreateTestConfiguredJarList(bootJars) + + }) +} + +// FixtureSetApexSystemServerJars sets the ApexSystemServerJars property in the global config. +func FixtureSetApexSystemServerJars(jars ...string) android.FixturePreparer { + return FixtureModifyGlobalConfig(func(dexpreoptConfig *GlobalConfig) { + dexpreoptConfig.ApexSystemServerJars = android.CreateTestConfiguredJarList(jars) }) } diff --git a/java/app.go b/java/app.go index fc1ace07b..06967690b 100755 --- a/java/app.go +++ b/java/app.go @@ -288,7 +288,7 @@ func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) { if minSdkVersion, err := a.MinSdkVersion(ctx).EffectiveVersion(ctx); err == nil { a.checkJniLibsSdkVersion(ctx, minSdkVersion) - android.CheckMinSdkVersion(a, ctx, minSdkVersion) + android.CheckMinSdkVersion(ctx, minSdkVersion, a.WalkPayloadDeps) } else { ctx.PropertyErrorf("min_sdk_version", "%s", err.Error()) } diff --git a/java/base.go b/java/base.go index 5d2927ac9..4780cc909 100644 --- a/java/base.go +++ b/java/base.go @@ -185,6 +185,10 @@ type DeviceProperties struct { // Defaults to sdk_version if not set. Min_sdk_version *string + // if not blank, set the maximum version of the sdk that the compiled artifacts will run against. + // Defaults to empty string "". See sdk_version for possible values. + Max_sdk_version *string + // if not blank, set the targetSdkVersion in the AndroidManifest.xml. // Defaults to sdk_version if not set. Target_sdk_version *string @@ -367,6 +371,7 @@ type Module struct { sdkVersion android.SdkSpec minSdkVersion android.SdkSpec + maxSdkVersion android.SdkSpec } func (j *Module) CheckStableSdkVersion(ctx android.BaseModuleContext) error { @@ -524,6 +529,13 @@ func (j *Module) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { return j.SdkVersion(ctx) } +func (j *Module) MaxSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { + maxSdkVersion := proptools.StringDefault(j.deviceProperties.Max_sdk_version, "") + // SdkSpecFrom returns SdkSpecPrivate for this, which may be confusing. + // TODO(b/208456999): ideally MaxSdkVersion should be an ApiLevel and not SdkSpec. + return android.SdkSpecFrom(ctx, maxSdkVersion) +} + func (j *Module) MinSdkVersionString() string { return j.minSdkVersion.Raw } @@ -1488,8 +1500,7 @@ func (j *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Modu } // Implements android.ApexModule -func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, - sdkVersion android.ApiLevel) error { +func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error { sdkSpec := j.MinSdkVersion(ctx) if !sdkSpec.Specified() { return fmt.Errorf("min_sdk_version is not specified") diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go index f63d81d6e..7eadfe6c3 100644 --- a/java/classpath_fragment.go +++ b/java/classpath_fragment.go @@ -84,11 +84,10 @@ func initClasspathFragment(c classpathFragment, classpathType classpathType) { // Matches definition of Jar in packages/modules/SdkExtensions/proto/classpaths.proto type classpathJar struct { - path string - classpath classpathType - // TODO(satayev): propagate min/max sdk versions for the jars - minSdkVersion int32 - maxSdkVersion int32 + path string + classpath classpathType + minSdkVersion string + maxSdkVersion string } // gatherPossibleApexModuleNamesAndStems returns a set of module and stem names from the @@ -120,10 +119,32 @@ func configuredJarListToClasspathJars(ctx android.ModuleContext, configuredJars jars := make([]classpathJar, 0, len(paths)*len(classpaths)) for i := 0; i < len(paths); i++ { for _, classpathType := range classpaths { - jars = append(jars, classpathJar{ + jar := classpathJar{ classpath: classpathType, path: paths[i], + } + ctx.VisitDirectDepsIf(func(m android.Module) bool { + return m.Name() == configuredJars.Jar(i) + }, func(m android.Module) { + if s, ok := m.(*SdkLibrary); ok { + // TODO(208456999): instead of mapping "current" to latest, min_sdk_version should never be set to "current" + if s.minSdkVersion.Specified() { + if s.minSdkVersion.ApiLevel.IsCurrent() { + jar.minSdkVersion = ctx.Config().LatestPreviewApiLevel().String() + } else { + jar.minSdkVersion = s.minSdkVersion.ApiLevel.String() + } + } + if s.maxSdkVersion.Specified() { + if s.maxSdkVersion.ApiLevel.IsCurrent() { + jar.maxSdkVersion = ctx.Config().LatestPreviewApiLevel().String() + } else { + jar.maxSdkVersion = s.maxSdkVersion.ApiLevel.String() + } + } + } }) + jars = append(jars, jar) } } return jars @@ -136,15 +157,15 @@ func (c *ClasspathFragmentBase) generateClasspathProtoBuildActions(ctx android.M c.outputFilepath = android.PathForModuleOut(ctx, outputFilename).OutputPath c.installDirPath = android.PathForModuleInstall(ctx, "etc", "classpaths") - generatedJson := android.PathForModuleOut(ctx, outputFilename+".json") - writeClasspathsJson(ctx, generatedJson, jars) + generatedTextproto := android.PathForModuleOut(ctx, outputFilename+".textproto") + writeClasspathsTextproto(ctx, generatedTextproto, jars) rule := android.NewRuleBuilder(pctx, ctx) rule.Command(). BuiltTool("conv_classpaths_proto"). Flag("encode"). - Flag("--format=json"). - FlagWithInput("--input=", generatedJson). + Flag("--format=textproto"). + FlagWithInput("--input=", generatedTextproto). FlagWithOutput("--output=", c.outputFilepath) rule.Build("classpath_fragment", "Compiling "+c.outputFilepath.String()) @@ -159,24 +180,18 @@ func (c *ClasspathFragmentBase) generateClasspathProtoBuildActions(ctx android.M ctx.SetProvider(ClasspathFragmentProtoContentInfoProvider, classpathProtoInfo) } -func writeClasspathsJson(ctx android.ModuleContext, output android.WritablePath, jars []classpathJar) { +func writeClasspathsTextproto(ctx android.ModuleContext, output android.WritablePath, jars []classpathJar) { var content strings.Builder - fmt.Fprintf(&content, "{\n") - fmt.Fprintf(&content, "\"jars\": [\n") - for idx, jar := range jars { - fmt.Fprintf(&content, "{\n") - fmt.Fprintf(&content, "\"path\": \"%s\",\n", jar.path) - fmt.Fprintf(&content, "\"classpath\": \"%s\"\n", jar.classpath) - - if idx < len(jars)-1 { - fmt.Fprintf(&content, "},\n") - } else { - fmt.Fprintf(&content, "}\n") - } + for _, jar := range jars { + fmt.Fprintf(&content, "jars {\n") + fmt.Fprintf(&content, "path: \"%s\"\n", jar.path) + fmt.Fprintf(&content, "classpath: %s\n", jar.classpath) + fmt.Fprintf(&content, "min_sdk_version: \"%s\"\n", jar.minSdkVersion) + fmt.Fprintf(&content, "max_sdk_version: \"%s\"\n", jar.maxSdkVersion) + fmt.Fprintf(&content, "}\n") } - fmt.Fprintf(&content, "]\n") - fmt.Fprintf(&content, "}\n") + android.WriteFileRule(ctx, output, content.String()) } diff --git a/java/config/config.go b/java/config/config.go index 273084c85..30c6f91aa 100644 --- a/java/config/config.go +++ b/java/config/config.go @@ -69,8 +69,6 @@ func init() { pctx.StaticVariable("JavacHeapSize", "2048M") pctx.StaticVariable("JavacHeapFlags", "-J-Xmx${JavacHeapSize}") pctx.StaticVariable("DexFlags", "-JXX:OnError='cat hs_err_pid%p.log' -JXX:CICompilerCount=6 -JXX:+UseDynamicNumberOfGCThreads") - // TODO(b/181095653): remove duplicated flags. - pctx.StaticVariable("DexJavaFlags", "-XX:OnError='cat hs_err_pid%p.log' -XX:CICompilerCount=6 -XX:+UseDynamicNumberOfGCThreads -Xmx2G") pctx.StaticVariable("CommonJdkFlags", strings.Join([]string{ `-Xmaxerrs 9999999`, diff --git a/java/dex.go b/java/dex.go index 6bf0143b1..1acfebd51 100644 --- a/java/dex.go +++ b/java/dex.go @@ -69,6 +69,9 @@ type DexProperties struct { // This defaults to reasonable value based on module and should not be set. // It exists only to support ART tests. Uncompress_dex *bool + + // Exclude kotlinc generate files: *.kotlin_module, *.kotlin_builtins. Defaults to false. + Exclude_kotlinc_generated_files *bool } type dexer struct { @@ -84,17 +87,12 @@ func (d *dexer) effectiveOptimizeEnabled() bool { return BoolDefault(d.dexProperties.Optimize.Enabled, d.dexProperties.Optimize.EnabledByDefault) } -func init() { - pctx.HostBinToolVariable("runWithTimeoutCmd", "run_with_timeout") - pctx.SourcePathVariable("jstackCmd", "${config.JavaToolchain}/jstack") -} - var d8, d8RE = pctx.MultiCommandRemoteStaticRules("d8", blueprint.RuleParams{ Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` + `$d8Template${config.D8Cmd} ${config.DexFlags} --output $outDir $d8Flags $in && ` + `$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` + - `${config.MergeZipsCmd} -D -stripFile "**/*.class" $out $outDir/classes.dex.jar $in`, + `${config.MergeZipsCmd} -D -stripFile "**/*.class" $mergeZipsFlags $out $outDir/classes.dex.jar $in`, CommandDeps: []string{ "${config.D8Cmd}", "${config.SoongZipCmd}", @@ -115,17 +113,14 @@ var d8, d8RE = pctx.MultiCommandRemoteStaticRules("d8", ExecStrategy: "${config.RED8ExecStrategy}", Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, }, - }, []string{"outDir", "d8Flags", "zipFlags"}, nil) + }, []string{"outDir", "d8Flags", "zipFlags", "mergeZipsFlags"}, nil) var r8, r8RE = pctx.MultiCommandRemoteStaticRules("r8", blueprint.RuleParams{ Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` + `rm -f "$outDict" && rm -rf "${outUsageDir}" && ` + `mkdir -p $$(dirname ${outUsage}) && ` + - // TODO(b/181095653): remove R8 timeout and go back to config.R8Cmd. - `${runWithTimeoutCmd} -timeout 30m -on_timeout '${jstackCmd} $$PID' -- ` + - `$r8Template${config.JavaCmd} ${config.DexJavaFlags} -cp ${config.R8Jar} ` + - `com.android.tools.r8.compatproguard.CompatProguard -injars $in --output $outDir ` + + `$r8Template${config.R8Cmd} ${config.DexFlags} -injars $in --output $outDir ` + `--no-data-resources ` + `-printmapping ${outDict} ` + `-printusage ${outUsage} ` + @@ -134,12 +129,11 @@ var r8, r8RE = pctx.MultiCommandRemoteStaticRules("r8", `${config.SoongZipCmd} -o ${outUsageZip} -C ${outUsageDir} -f ${outUsage} && ` + `rm -rf ${outUsageDir} && ` + `$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` + - `${config.MergeZipsCmd} -D -stripFile "**/*.class" $out $outDir/classes.dex.jar $in`, + `${config.MergeZipsCmd} -D -stripFile "**/*.class" $mergeZipsFlags $out $outDir/classes.dex.jar $in`, CommandDeps: []string{ - "${config.R8Jar}", + "${config.R8Cmd}", "${config.SoongZipCmd}", "${config.MergeZipsCmd}", - "${runWithTimeoutCmd}", }, }, map[string]*remoteexec.REParams{ "$r8Template": &remoteexec.REParams{ @@ -165,7 +159,7 @@ var r8, r8RE = pctx.MultiCommandRemoteStaticRules("r8", Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, }, }, []string{"outDir", "outDict", "outUsage", "outUsageZip", "outUsageDir", - "r8Flags", "zipFlags"}, []string{"implicits"}) + "r8Flags", "zipFlags", "mergeZipsFlags"}, []string{"implicits"}) func (d *dexer) dexCommonFlags(ctx android.ModuleContext, minSdkVersion android.SdkSpec) []string { flags := d.dexProperties.Dxflags @@ -290,6 +284,12 @@ func (d *dexer) compileDex(ctx android.ModuleContext, flags javaBuilderFlags, mi commonFlags := d.dexCommonFlags(ctx, minSdkVersion) + // Exclude kotlinc generated files when "exclude_kotlinc_generated_files" is set to true. + mergeZipsFlags := "" + if proptools.BoolDefault(d.dexProperties.Exclude_kotlinc_generated_files, false) { + mergeZipsFlags = "-stripFile META-INF/*.kotlin_module -stripFile **/*.kotlin_builtins" + } + useR8 := d.effectiveOptimizeEnabled() if useR8 { proguardDictionary := android.PathForModuleOut(ctx, "proguard_dictionary") @@ -302,13 +302,14 @@ func (d *dexer) compileDex(ctx android.ModuleContext, flags javaBuilderFlags, mi r8Flags, r8Deps := d.r8Flags(ctx, flags) rule := r8 args := map[string]string{ - "r8Flags": strings.Join(append(commonFlags, r8Flags...), " "), - "zipFlags": zipFlags, - "outDict": proguardDictionary.String(), - "outUsageDir": proguardUsageDir.String(), - "outUsage": proguardUsage.String(), - "outUsageZip": proguardUsageZip.String(), - "outDir": outDir.String(), + "r8Flags": strings.Join(append(commonFlags, r8Flags...), " "), + "zipFlags": zipFlags, + "outDict": proguardDictionary.String(), + "outUsageDir": proguardUsageDir.String(), + "outUsage": proguardUsage.String(), + "outUsageZip": proguardUsageZip.String(), + "outDir": outDir.String(), + "mergeZipsFlags": mergeZipsFlags, } if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_R8") { rule = r8RE @@ -336,9 +337,10 @@ func (d *dexer) compileDex(ctx android.ModuleContext, flags javaBuilderFlags, mi Input: classesJar, Implicits: d8Deps, Args: map[string]string{ - "d8Flags": strings.Join(append(commonFlags, d8Flags...), " "), - "zipFlags": zipFlags, - "outDir": outDir.String(), + "d8Flags": strings.Join(append(commonFlags, d8Flags...), " "), + "zipFlags": zipFlags, + "outDir": outDir.String(), + "mergeZipsFlags": mergeZipsFlags, }, }) } diff --git a/java/java.go b/java/java.go index 02e06e0c0..a61ddf426 100644 --- a/java/java.go +++ b/java/java.go @@ -487,6 +487,7 @@ func shouldUncompressDex(ctx android.ModuleContext, dexpreopter *dexpreopter) bo func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.sdkVersion = j.SdkVersion(ctx) j.minSdkVersion = j.MinSdkVersion(ctx) + j.maxSdkVersion = j.MaxSdkVersion(ctx) apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) if !apexInfo.IsForPlatform() { diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go index cf266b80b..ca87f92fd 100644 --- a/java/platform_bootclasspath.go +++ b/java/platform_bootclasspath.go @@ -68,7 +68,6 @@ type platformBootclasspathProperties struct { func platformBootclasspathFactory() android.SingletonModule { m := &platformBootclasspathModule{} m.AddProperties(&m.properties) - // TODO(satayev): split apex jars into separate configs. initClasspathFragment(m, BOOTCLASSPATH) android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon) return m diff --git a/java/sdk_library.go b/java/sdk_library.go index 751a71d0c..c6747c730 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -1122,6 +1122,22 @@ func (module *SdkLibrary) getGeneratedApiScopes(ctx android.EarlyModuleContext) return generatedScopes } +var _ android.ModuleWithMinSdkVersionCheck = (*SdkLibrary)(nil) + +func (module *SdkLibrary) CheckMinSdkVersion(ctx android.ModuleContext) { + android.CheckMinSdkVersion(ctx, module.MinSdkVersion(ctx).ApiLevel, func(c android.ModuleContext, do android.PayloadDepsCallback) { + ctx.WalkDeps(func(child android.Module, parent android.Module) bool { + isExternal := !module.depIsInSameApex(ctx, child) + if am, ok := child.(android.ApexModule); ok { + if !do(ctx, parent, am, isExternal) { + return false + } + } + return !isExternal + }) + }) +} + type sdkLibraryComponentTag struct { blueprint.BaseDependencyTag name string @@ -1207,6 +1223,10 @@ func (module *SdkLibrary) OutputFiles(tag string) (android.Paths, error) { } func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { + if proptools.String(module.deviceProperties.Min_sdk_version) != "" { + module.CheckMinSdkVersion(ctx) + } + module.generateCommonBuildActions(ctx) // Only build an implementation library if required. @@ -2466,12 +2486,12 @@ func (module *sdkLibraryXml) GenerateAndroidBuildActions(ctx android.ModuleConte func (module *sdkLibraryXml) AndroidMkEntries() []android.AndroidMkEntries { if module.hideApexVariantFromMake { - return []android.AndroidMkEntries{android.AndroidMkEntries{ + return []android.AndroidMkEntries{{ Disabled: true, }} } - return []android.AndroidMkEntries{android.AndroidMkEntries{ + return []android.AndroidMkEntries{{ Class: "ETC", OutputFile: android.OptionalPathForPath(module.outputFilePath), ExtraEntries: []android.AndroidMkExtraEntriesFunc{ diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go index 3cf4987e1..f8717c066 100644 --- a/java/sdk_library_test.go +++ b/java/sdk_library_test.go @@ -47,6 +47,7 @@ func TestJavaSdkLibrary(t *testing.T) { name: "bar", srcs: ["a.java", "b.java"], api_packages: ["bar"], + exclude_kotlinc_generated_files: true, } java_library { name: "baz", @@ -159,6 +160,14 @@ func TestJavaSdkLibrary(t *testing.T) { sdkLibs := quxLib.ClassLoaderContexts().UsesLibs() android.AssertDeepEquals(t, "qux exports", []string{"foo", "bar", "fred", "quuz"}, sdkLibs) } + + fooDexJar := result.ModuleForTests("foo", "android_common").Rule("d8") + // tests if kotlinc generated files are NOT excluded from output of foo. + android.AssertStringDoesNotContain(t, "foo dex", fooDexJar.BuildParams.Args["mergeZipsFlags"], "-stripFile META-INF/*.kotlin_module") + + barDexJar := result.ModuleForTests("bar", "android_common").Rule("d8") + // tests if kotlinc generated files are excluded from output of bar. + android.AssertStringDoesContain(t, "bar dex", barDexJar.BuildParams.Args["mergeZipsFlags"], "-stripFile META-INF/*.kotlin_module") } func TestJavaSdkLibrary_StubOrImplOnlyLibs(t *testing.T) { @@ -958,3 +967,87 @@ func TestJavaSdkLibraryDist(t *testing.T) { }) } } + +func TestSdkLibrary_CheckMinSdkVersion(t *testing.T) { + preparer := android.GroupFixturePreparers( + PrepareForTestWithJavaBuildComponents, + PrepareForTestWithJavaDefaultModules, + PrepareForTestWithJavaSdkLibraryFiles, + ) + + preparer.RunTestWithBp(t, ` + java_sdk_library { + name: "sdklib", + srcs: ["a.java"], + static_libs: ["util"], + min_sdk_version: "30", + unsafe_ignore_missing_latest_api: true, + } + + java_library { + name: "util", + srcs: ["a.java"], + min_sdk_version: "30", + } + `) + + preparer. + RunTestWithBp(t, ` + java_sdk_library { + name: "sdklib", + srcs: ["a.java"], + libs: ["util"], + impl_only_libs: ["util"], + stub_only_libs: ["util"], + stub_only_static_libs: ["util"], + min_sdk_version: "30", + unsafe_ignore_missing_latest_api: true, + } + + java_library { + name: "util", + srcs: ["a.java"], + } + `) + + preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "util".*should support min_sdk_version\(30\)`)). + RunTestWithBp(t, ` + java_sdk_library { + name: "sdklib", + srcs: ["a.java"], + static_libs: ["util"], + min_sdk_version: "30", + unsafe_ignore_missing_latest_api: true, + } + + java_library { + name: "util", + srcs: ["a.java"], + min_sdk_version: "31", + } + `) + + preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "another_util".*should support min_sdk_version\(30\)`)). + RunTestWithBp(t, ` + java_sdk_library { + name: "sdklib", + srcs: ["a.java"], + static_libs: ["util"], + min_sdk_version: "30", + unsafe_ignore_missing_latest_api: true, + } + + java_library { + name: "util", + srcs: ["a.java"], + static_libs: ["another_util"], + min_sdk_version: "30", + } + + java_library { + name: "another_util", + srcs: ["a.java"], + min_sdk_version: "31", + } + `) +} diff --git a/java/systemserver_classpath_fragment.go b/java/systemserver_classpath_fragment.go index 10dbd01e2..be28fe9c2 100644 --- a/java/systemserver_classpath_fragment.go +++ b/java/systemserver_classpath_fragment.go @@ -72,10 +72,15 @@ func (s *SystemServerClasspathModule) ShouldSupportSdkVersion(ctx android.BaseMo } type systemServerClasspathFragmentProperties struct { - // The contents of this systemserverclasspath_fragment, could be either java_library, or java_sdk_library. + // List of system_server classpath jars, could be either java_library, or java_sdk_library. // // The order of this list matters as it is the order that is used in the SYSTEMSERVERCLASSPATH. Contents []string + + // List of jars that system_server loads dynamically using separate classloaders. + // + // The order does not matter. + Standalone_contents []string } func systemServerClasspathFactory() android.Module { @@ -88,8 +93,12 @@ func systemServerClasspathFactory() android.Module { } func (s *SystemServerClasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { - if len(s.properties.Contents) == 0 { - ctx.PropertyErrorf("contents", "empty contents are not allowed") + if len(s.properties.Contents) == 0 && len(s.properties.Standalone_contents) == 0 { + ctx.PropertyErrorf("contents", "Either contents or standalone_contents needs to be non-empty") + } + + if s.ShouldIgnore() { + return } configuredJars := s.configuredJars(ctx) @@ -128,8 +137,17 @@ func IsSystemServerClasspathFragmentContentDepTag(tag blueprint.DependencyTag) b func (s *SystemServerClasspathModule) ComponentDepsMutator(ctx android.BottomUpMutatorContext) { module := ctx.Module() + var deps []string + deps = append(deps, s.properties.Contents...) + deps = append(deps, s.properties.Standalone_contents...) - for _, name := range s.properties.Contents { + for _, name := range deps { ctx.AddDependency(module, systemServerClasspathFragmentContentDepTag, name) } } + +func (s *SystemServerClasspathModule) ShouldIgnore() bool { + // Ignore this `systemserverclasspath_fragment` if it only contains `standalone_contents` because + // it is for T and above. + return len(s.properties.Contents) == 0 +} diff --git a/java/systemserver_classpath_fragment_test.go b/java/systemserver_classpath_fragment_test.go index 9ad50dd4a..ba328e7b1 100644 --- a/java/systemserver_classpath_fragment_test.go +++ b/java/systemserver_classpath_fragment_test.go @@ -99,7 +99,7 @@ func TestPlatformSystemServerClasspathModule_AndroidMkEntries(t *testing.T) { func TestSystemServerClasspathFragmentWithoutContents(t *testing.T) { prepareForTestWithSystemServerClasspath. ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( - `\Qempty contents are not allowed\E`)). + `\QEither contents or standalone_contents needs to be non-empty\E`)). RunTestWithBp(t, ` systemserverclasspath_fragment { name: "systemserverclasspath-fragment", diff --git a/rust/rust.go b/rust/rust.go index f068b3d7b..cdeecc191 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -328,10 +328,6 @@ func (mod *Module) SdkVersion() string { return "" } -func (mod *Module) MinSdkVersion() string { - return "" -} - func (mod *Module) AlwaysSdk() bool { return false } @@ -1276,15 +1272,13 @@ func (mod *Module) HostToolPath() android.OptionalPath { var _ android.ApexModule = (*Module)(nil) -func (mod *Module) minSdkVersion() string { +func (mod *Module) MinSdkVersion() string { return String(mod.Properties.Min_sdk_version) } -var _ android.ApexModule = (*Module)(nil) - // Implements android.ApexModule func (mod *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error { - minSdkVersion := mod.minSdkVersion() + minSdkVersion := mod.MinSdkVersion() if minSdkVersion == "apex_inherit" { return nil } diff --git a/scripts/OWNERS b/scripts/OWNERS index 2b9c2ded9..573134ed8 100644 --- a/scripts/OWNERS +++ b/scripts/OWNERS @@ -3,4 +3,4 @@ per-file build-mainline-modules.sh = ngeoffray@google.com,paulduffin@google.com, per-file build-aml-prebuilts.sh = ngeoffray@google.com,paulduffin@google.com,mast@google.com per-file construct_context.py = ngeoffray@google.com,calin@google.com,mathieuc@google.com,skvadrik@google.com per-file conv_linker_config.py = kiyoungkim@google.com, jiyong@google.com, jooyung@google.com -per-file gen_ndk*.sh = sophiez@google.com, allenhair@google.com +per-file gen_ndk*.sh,gen_java*.sh = sophiez@google.com, allenhair@google.com
\ No newline at end of file diff --git a/scripts/gen_java_usedby_apex.sh b/scripts/gen_java_usedby_apex.sh new file mode 100755 index 000000000..e3985414b --- /dev/null +++ b/scripts/gen_java_usedby_apex.sh @@ -0,0 +1,48 @@ +#!/bin/bash -e + +# Copyright 2020 Google Inc. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +printHelp() { + echo "**************************** Usage Instructions ****************************" + echo "This script is used to generate the Mainline modules used-by Java symbols." + echo "" + echo "To run this script use: ./gen_java_usedby_apex.sh \$BINARY_DEXDEPS_PATH \$OUTPUT_FILE_PATH \$JAR_AND_APK_LIST" + echo "For example: If all jar and apk files are '/myJar.jar /myApk.apk' and output write to /myModule.txt then the command would be:" + echo "./gen_java_usedby_apex.sh \$BINARY_DEXDEPS_PATH /myModule.txt /myJar.jar /myApk.apk" +} + +genUsedByList() { + dexdeps="$1" + shift + out="$1" + shift + rm -f "$out" + touch "$out" + echo "<externals>" >> "$out" + for x in "$@"; do + "$dexdeps" "$x" >> "$out" || echo "</external>" >> "$out" + done + echo "</externals>" >> "$out" +} + +if [[ "$1" == "help" ]] +then + printHelp +elif [[ "$#" -lt 2 ]] +then + echo "Wrong argument length. Expecting at least 2 argument representing dexdeps path, output path, followed by a list of jar or apk files in the Mainline module." +else + genUsedByList "$@" +fi
\ No newline at end of file diff --git a/sdk/sdk.go b/sdk/sdk.go index b1c8aebf9..d8196fffc 100644 --- a/sdk/sdk.go +++ b/sdk/sdk.go @@ -257,7 +257,13 @@ func newSdkModule(moduleExports bool) *sdk { // Create an instance of the dynamically created struct that contains all the // properties for the member type specific list properties. s.dynamicMemberTypeListProperties = s.dynamicSdkMemberTypes.createMemberListProperties() - s.AddProperties(&s.properties, s.dynamicMemberTypeListProperties) + + ignoredProperties := struct { + // `systemserverclasspath_fragments` is for T and above. + Systemserverclasspath_fragments []string + }{} + + s.AddProperties(&s.properties, s.dynamicMemberTypeListProperties, &ignoredProperties) // Make sure that the prebuilt visibility property is verified for errors. android.AddVisibilityProperty(s, "prebuilt_visibility", &s.properties.Prebuilt_visibility) |