diff options
141 files changed, 2229 insertions, 297 deletions
diff --git a/Android.bp b/Android.bp index 1012dbabf..9d5b07def 100644 --- a/Android.bp +++ b/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + subdirs = [ "androidmk", "bpfix", diff --git a/android/Android.bp b/android/Android.bp index eabb137a5..00139d8ab 100644 --- a/android/Android.bp +++ b/android/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-android", pkgPath: "android/soong/android", diff --git a/android/bazel_handler.go b/android/bazel_handler.go index 4a2511972..a5c4bedc5 100644 --- a/android/bazel_handler.go +++ b/android/bazel_handler.go @@ -234,6 +234,13 @@ func (context *bazelContext) issueBazelCommand(runName bazel.RunName, command st cmdFlags = append(cmdFlags, labels...) cmdFlags = append(cmdFlags, "--package_path=%workspace%/"+context.intermediatesDir()) cmdFlags = append(cmdFlags, "--profile="+shared.BazelMetricsFilename(context, runName)) + // Set default platforms to canonicalized values for mixed builds requests. If these are set + // in the bazelrc, they will have values that are non-canonicalized, and thus be invalid. + // The actual platform values here may be overridden by configuration transitions from the buildroot. + cmdFlags = append(cmdFlags, + fmt.Sprintf("--platforms=%s", canonicalizeLabel("//build/bazel/platforms:generic_x86_64"))) + cmdFlags = append(cmdFlags, + fmt.Sprintf("--extra_toolchains=%s", canonicalizeLabel("//prebuilts/clang/host/linux-x86:all"))) cmdFlags = append(cmdFlags, extraFlags...) bazelCmd := exec.Command(context.bazelPath, cmdFlags...) @@ -460,7 +467,6 @@ func (context *bazelContext) InvokeBazel() error { return err } - fmt.Printf("Build statements %s", context.buildStatements) // Clear requests. context.requests = map[cqueryKey]bool{} return nil diff --git a/android/config.go b/android/config.go index e0f3a91f9..50e39d7e9 100644 --- a/android/config.go +++ b/android/config.go @@ -1413,6 +1413,14 @@ func (c *deviceConfig) VendorSnapshotModules() map[string]bool { return c.config.productVariables.VendorSnapshotModules } +func (c *deviceConfig) DirectedRecoverySnapshot() bool { + return c.config.productVariables.DirectedRecoverySnapshot +} + +func (c *deviceConfig) RecoverySnapshotModules() map[string]bool { + return c.config.productVariables.RecoverySnapshotModules +} + // The ConfiguredJarList struct provides methods for handling a list of (apex, jar) pairs. // Such lists are used in the build system for things like bootclasspath jars or system server jars. // The apex part is either an apex name, or a special names "platform" or "system_ext". Jar is a diff --git a/android/filegroup.go b/android/filegroup.go index 7a6cc4ffc..674a196cb 100644 --- a/android/filegroup.go +++ b/android/filegroup.go @@ -17,8 +17,6 @@ package android import ( "android/soong/bazel" "strings" - - "github.com/google/blueprint/proptools" ) func init() { @@ -28,7 +26,6 @@ func init() { // https://docs.bazel.build/versions/master/be/general.html#filegroup type bazelFilegroupAttributes struct { - Name *string Srcs bazel.LabelList } @@ -50,20 +47,19 @@ func (bfg *bazelFilegroup) Name() string { func (bfg *bazelFilegroup) GenerateAndroidBuildActions(ctx ModuleContext) {} -// TODO: Create helper functions to avoid this boilerplate. func FilegroupBp2Build(ctx TopDownMutatorContext) { fg, ok := ctx.Module().(*fileGroup) - if !ok { + if !ok || !fg.properties.Bazel_module.Bp2build_available { return } - name := "__bp2build__" + fg.base().BaseModuleName() - ctx.CreateModule(BazelFileGroupFactory, &bazelFilegroupAttributes{ - Name: proptools.StringPtr(name), + attrs := &bazelFilegroupAttributes{ Srcs: BazelLabelForModuleSrcExcludes(ctx, fg.properties.Srcs, fg.properties.Exclude_srcs), - }, &bazel.BazelTargetModuleProperties{ - Rule_class: "filegroup", - }) + } + + props := bazel.NewBazelTargetModuleProperties(fg.Name(), "filegroup", "") + + ctx.CreateBazelTargetModule(BazelFileGroupFactory, props, attrs) } type fileGroupProperties struct { diff --git a/android/module.go b/android/module.go index 1409d44b1..bf74cad07 100644 --- a/android/module.go +++ b/android/module.go @@ -2374,6 +2374,16 @@ func (b *baseModuleContext) FinalModule() Module { return b.bp.FinalModule().(Module) } +// IsMetaDependencyTag returns true for cross-cutting metadata dependencies. +func IsMetaDependencyTag(tag blueprint.DependencyTag) bool { + if tag == licenseKindTag { + return true + } else if tag == licensesTag { + return true + } + return false +} + // A regexp for removing boilerplate from BaseDependencyTag from the string representation of // a dependency tag. var tagCleaner = regexp.MustCompile(`\QBaseDependencyTag:{}\E(, )?`) diff --git a/android/mutator.go b/android/mutator.go index 15be65f9a..c38719334 100644 --- a/android/mutator.go +++ b/android/mutator.go @@ -15,7 +15,10 @@ package android import ( + "android/soong/bazel" + "fmt" "reflect" + "strings" "github.com/google/blueprint" "github.com/google/blueprint/proptools" @@ -275,6 +278,12 @@ type TopDownMutatorContext interface { // CreateModule creates a new module by calling the factory method for the specified moduleType, and applies // the specified property structs to it as if the properties were set in a blueprint file. CreateModule(ModuleFactory, ...interface{}) Module + + // CreateBazelTargetModule creates a BazelTargetModule by calling the + // factory method, just like in CreateModule, but also requires + // BazelTargetModuleProperties containing additional metadata for the + // bp2build codegenerator. + CreateBazelTargetModule(ModuleFactory, bazel.BazelTargetModuleProperties, interface{}) BazelTargetModule } type topDownMutatorContext struct { @@ -502,6 +511,21 @@ func registerDepsMutatorBp2Build(ctx RegisterMutatorsContext) { ctx.BottomUp("deps", depsMutator).Parallel() } +func (t *topDownMutatorContext) CreateBazelTargetModule( + factory ModuleFactory, + bazelProps bazel.BazelTargetModuleProperties, + attrs interface{}) BazelTargetModule { + if !strings.HasPrefix(*bazelProps.Name, bazel.BazelTargetModuleNamePrefix) { + panic(fmt.Errorf( + "bp2build error: the bazel target module name must start with '%s': %s", + bazel.BazelTargetModuleNamePrefix, + *bazelProps.Name, + )) + } + + return t.CreateModule(factory, &bazelProps, attrs).(BazelTargetModule) +} + func (t *topDownMutatorContext) AppendProperties(props ...interface{}) { for _, p := range props { err := proptools.AppendMatchingProperties(t.Module().base().customizableProperties, diff --git a/android/paths.go b/android/paths.go index 44221be70..c3fa61a09 100644 --- a/android/paths.go +++ b/android/paths.go @@ -1949,3 +1949,28 @@ type DataPath struct { // The install path of the data file, relative to the install root. RelativeInstallPath string } + +// PathsIfNonNil returns a Paths containing only the non-nil input arguments. +func PathsIfNonNil(paths ...Path) Paths { + if len(paths) == 0 { + // Fast path for empty argument list + return nil + } else if len(paths) == 1 { + // Fast path for a single argument + if paths[0] != nil { + return paths + } else { + return nil + } + } + ret := make(Paths, 0, len(paths)) + for _, path := range paths { + if path != nil { + ret = append(ret, path) + } + } + if len(ret) == 0 { + return nil + } + return ret +} diff --git a/android/soongconfig/Android.bp b/android/soongconfig/Android.bp index 6bb68eb2d..e7fa5a036 100644 --- a/android/soongconfig/Android.bp +++ b/android/soongconfig/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-android-soongconfig", pkgPath: "android/soong/android/soongconfig", diff --git a/android/variable.go b/android/variable.go index 9b3ed1765..e76d68397 100644 --- a/android/variable.go +++ b/android/variable.go @@ -121,10 +121,6 @@ type variableProperties struct { Cppflags []string } - Use_lmkd_stats_log struct { - Cflags []string - } - Arc struct { Cflags []string `android:"arch_variant"` Exclude_srcs []string `android:"arch_variant"` @@ -240,7 +236,6 @@ type productVariables struct { Treble_linker_namespaces *bool `json:",omitempty"` Enforce_vintf_manifest *bool `json:",omitempty"` Uml *bool `json:",omitempty"` - Use_lmkd_stats_log *bool `json:",omitempty"` Arc *bool `json:",omitempty"` MinimizeJavaDebugInfo *bool `json:",omitempty"` @@ -312,6 +307,9 @@ type productVariables struct { DirectedVendorSnapshot bool `json:",omitempty"` VendorSnapshotModules map[string]bool `json:",omitempty"` + DirectedRecoverySnapshot bool `json:",omitempty"` + RecoverySnapshotModules map[string]bool `json:",omitempty"` + BoardVendorSepolicyDirs []string `json:",omitempty"` BoardOdmSepolicyDirs []string `json:",omitempty"` BoardReqdMaskPolicy []string `json:",omitempty"` diff --git a/androidmk/Android.bp b/androidmk/Android.bp index 70fc1f75c..f04d01c4e 100644 --- a/androidmk/Android.bp +++ b/androidmk/Android.bp @@ -16,6 +16,10 @@ // androidmk Android.mk to Blueprints translator // +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + blueprint_go_binary { name: "androidmk", srcs: [ diff --git a/apex/Android.bp b/apex/Android.bp index b6fdcf415..8a2edebdb 100644 --- a/apex/Android.bp +++ b/apex/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-apex", pkgPath: "android/soong/apex", diff --git a/apex/allowed_deps.txt b/apex/allowed_deps.txt index 5d00e06a5..aee3fc496 100644 --- a/apex/allowed_deps.txt +++ b/apex/allowed_deps.txt @@ -39,6 +39,7 @@ android.hardware.media.c2@1.0(minSdkVersion:29) android.hardware.media.c2@1.1(minSdkVersion:29) android.hardware.media.omx@1.0(minSdkVersion:29) android.hardware.media@1.0(minSdkVersion:29) +android.hardware.neuralnetworks-V1-ndk_platform(minSdkVersion:30) android.hardware.neuralnetworks@1.0(minSdkVersion:30) android.hardware.neuralnetworks@1.1(minSdkVersion:30) android.hardware.neuralnetworks@1.2(minSdkVersion:30) @@ -499,6 +500,7 @@ neuralnetworks_utils_hal_1_0(minSdkVersion:30) neuralnetworks_utils_hal_1_1(minSdkVersion:30) neuralnetworks_utils_hal_1_2(minSdkVersion:30) neuralnetworks_utils_hal_1_3(minSdkVersion:30) +neuralnetworks_utils_hal_aidl(minSdkVersion:30) neuralnetworks_utils_hal_common(minSdkVersion:30) neuralnetworks_utils_hal_service(minSdkVersion:30) no_op(minSdkVersion:current) diff --git a/apex/apex_test.go b/apex/apex_test.go index 9f8cd0654..181946bf7 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -4364,7 +4364,7 @@ func TestPrebuiltExportDexImplementationJars(t *testing.T) { checkDexJarBuildPath := func(t *testing.T, ctx *android.TestContext, name string) { // Make sure the import has been given the correct path to the dex jar. - p := ctx.ModuleForTests(name, "android_common_myapex").Module().(java.Dependency) + p := ctx.ModuleForTests(name, "android_common_myapex").Module().(java.UsesLibraryDependency) dexJarBuildPath := p.DexJarBuildPath() if expected, actual := ".intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar", android.NormalizePathForTesting(dexJarBuildPath); actual != expected { t.Errorf("Incorrect DexJarBuildPath value '%s', expected '%s'", actual, expected) @@ -4495,6 +4495,12 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { } } + checkHiddenAPIIndexInputs := func(t *testing.T, ctx *android.TestContext, expectedInputs string) { + hiddenAPIIndex := ctx.SingletonForTests("hiddenapi_index") + indexRule := hiddenAPIIndex.Rule("singleton-merged-hiddenapi-index") + java.CheckHiddenAPIRuleInputs(t, expectedInputs, indexRule) + } + t.Run("prebuilt only", func(t *testing.T) { bp := ` prebuilt_apex { @@ -4519,6 +4525,11 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { ctx := testDexpreoptWithApexes(t, bp, "", transform) checkBootDexJarPath(t, ctx, ".intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar") + + // Make sure that the dex file from the prebuilt_apex contributes to the hiddenapi index file. + checkHiddenAPIIndexInputs(t, ctx, ` +.intermediates/libfoo/android_common_myapex/hiddenapi/index.csv +`) }) t.Run("prebuilt with source library preferred", func(t *testing.T) { @@ -4588,6 +4599,11 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { ctx := testDexpreoptWithApexes(t, bp, "", transform) checkBootDexJarPath(t, ctx, ".intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar") + + // Make sure that the dex file from the prebuilt_apex contributes to the hiddenapi index file. + checkHiddenAPIIndexInputs(t, ctx, ` +.intermediates/prebuilt_libfoo/android_common_myapex/hiddenapi/index.csv +`) }) t.Run("prebuilt with source apex preferred", func(t *testing.T) { @@ -4631,7 +4647,12 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { ` ctx := testDexpreoptWithApexes(t, bp, "", transform) - checkBootDexJarPath(t, ctx, ".intermediates/libfoo/android_common_apex10000/aligned/libfoo.jar") + checkBootDexJarPath(t, ctx, ".intermediates/libfoo/android_common_apex10000/hiddenapi/libfoo.jar") + + // Make sure that the dex file from the prebuilt_apex contributes to the hiddenapi index file. + checkHiddenAPIIndexInputs(t, ctx, ` +.intermediates/libfoo/android_common_apex10000/hiddenapi/index.csv +`) }) t.Run("prebuilt preferred with source apex disabled", func(t *testing.T) { @@ -4678,6 +4699,11 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { ctx := testDexpreoptWithApexes(t, bp, "", transform) checkBootDexJarPath(t, ctx, ".intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar") + + // Make sure that the dex file from the prebuilt_apex contributes to the hiddenapi index file. + checkHiddenAPIIndexInputs(t, ctx, ` +.intermediates/prebuilt_libfoo/android_common_prebuilt_myapex/hiddenapi/index.csv +`) }) } @@ -6304,6 +6330,7 @@ func testDexpreoptWithApexes(t *testing.T, bp, errmsg string, transformDexpreopt android.RegisterPrebuiltMutators(ctx) cc.RegisterRequiredBuildComponentsForTest(ctx) java.RegisterRequiredBuildComponentsForTest(ctx) + java.RegisterHiddenApiSingletonComponents(ctx) ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators) ctx.PreDepsMutators(RegisterPreDepsMutators) ctx.PostDepsMutators(RegisterPostDepsMutators) @@ -6315,6 +6342,11 @@ func testDexpreoptWithApexes(t *testing.T, bp, errmsg string, transformDexpreopt transformDexpreoptConfig(dexpreoptConfig) dexpreopt.SetTestGlobalConfig(config, dexpreoptConfig) + // Make sure that any changes to these dexpreopt properties are mirrored in the corresponding + // product variables. + config.TestProductVariables.BootJars = dexpreoptConfig.BootJars + config.TestProductVariables.UpdatableBootJars = dexpreoptConfig.UpdatableBootJars + _, errs := ctx.ParseBlueprintsFiles("Android.bp") android.FailIfErrored(t, errs) diff --git a/apex/builder.go b/apex/builder.go index 16ca74cf2..2663a679f 100644 --- a/apex/builder.go +++ b/apex/builder.go @@ -700,15 +700,20 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { }) a.apisUsedByModuleFile = apisUsedbyOutputFile + var libNames []string + for _, f := range a.filesInfo { + if f.class == nativeSharedLib { + libNames = append(libNames, f.stem()) + } + } apisBackedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_backing.txt") ndkLibraryList := android.PathForSource(ctx, "system/core/rootdir/etc/public.libraries.android.txt") rule := android.NewRuleBuilder(pctx, ctx) rule.Command(). Tool(android.PathForSource(ctx, "build/soong/scripts/gen_ndk_backedby_apex.sh")). - Text(imageDir.String()). - Implicits(implicitInputs). Output(apisBackedbyOutputFile). - Input(ndkLibraryList) + Input(ndkLibraryList). + Flags(libNames) rule.Build("ndk_backedby_list", "Generate API libraries backed by Apex") a.apisBackedByModuleFile = apisBackedbyOutputFile diff --git a/apex/prebuilt.go b/apex/prebuilt.go index 314995205..041afb33a 100644 --- a/apex/prebuilt.go +++ b/apex/prebuilt.go @@ -260,12 +260,36 @@ func prebuiltSelectSourceMutator(ctx android.BottomUpMutatorContext) { } } +type exportedDependencyTag struct { + blueprint.BaseDependencyTag + name string +} + +// Mark this tag so dependencies that use it are excluded from visibility enforcement. +// +// This does allow any prebuilt_apex to reference any module which does open up a small window for +// restricted visibility modules to be referenced from the wrong prebuilt_apex. However, doing so +// avoids opening up a much bigger window by widening the visibility of modules that need files +// provided by the prebuilt_apex to include all the possible locations they may be defined, which +// could include everything below vendor/. +// +// A prebuilt_apex that references a module via this tag will have to contain the appropriate files +// corresponding to that module, otherwise it will fail when attempting to retrieve the files from +// the .apex file. It will also have to be included in the module's apex_available property too. +// That makes it highly unlikely that a prebuilt_apex would reference a restricted module +// incorrectly. +func (t exportedDependencyTag) ExcludeFromVisibilityEnforcement() {} + +var ( + exportedJavaLibTag = exportedDependencyTag{name: "exported_java_lib"} +) + func (p *Prebuilt) DepsMutator(ctx android.BottomUpMutatorContext) { // Add dependencies onto the java modules that represent the java libraries that are provided by // and exported from this prebuilt apex. for _, lib := range p.properties.Exported_java_libs { dep := prebuiltApexExportedModuleName(ctx, lib) - ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(), javaLibTag, dep) + ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(), exportedJavaLibTag, dep) } } @@ -305,7 +329,7 @@ func (p *Prebuilt) ApexInfoMutator(mctx android.TopDownMutatorContext) { var dependencies []android.ApexModule mctx.VisitDirectDeps(func(m android.Module) { tag := mctx.OtherModuleDependencyTag(m) - if tag == javaLibTag { + if tag == exportedJavaLibTag { depName := mctx.OtherModuleName(m) // It is an error if the other module is not a prebuilt. diff --git a/bazel/Android.bp b/bazel/Android.bp index d222d9810..117fd46d9 100644 --- a/bazel/Android.bp +++ b/bazel/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-bazel", pkgPath: "android/soong/bazel", diff --git a/bazel/properties.go b/bazel/properties.go index 5b98d159d..8055306b2 100644 --- a/bazel/properties.go +++ b/bazel/properties.go @@ -14,9 +14,17 @@ package bazel +import ( + "fmt" + "strings" +) + type bazelModuleProperties struct { // The label of the Bazel target replacing this Soong module. Label string + + // If true, bp2build will generate the converted Bazel target for this module. + Bp2build_available bool } // Properties contains common module properties for Bazel migration purposes. @@ -29,6 +37,8 @@ type Properties struct { // BazelTargetModuleProperties contain properties and metadata used for // Blueprint to BUILD file conversion. type BazelTargetModuleProperties struct { + Name *string + // The Bazel rule class for this target. Rule_class string @@ -36,6 +46,23 @@ type BazelTargetModuleProperties struct { Bzl_load_location string } +const BazelTargetModuleNamePrefix = "__bp2build__" + +func NewBazelTargetModuleProperties(name string, ruleClass string, bzlLoadLocation string) BazelTargetModuleProperties { + if strings.HasPrefix(name, BazelTargetModuleNamePrefix) { + panic(fmt.Errorf( + "The %s name prefix is added automatically, do not set it manually: %s", + BazelTargetModuleNamePrefix, + name)) + } + name = BazelTargetModuleNamePrefix + name + return BazelTargetModuleProperties{ + Name: &name, + Rule_class: ruleClass, + Bzl_load_location: bzlLoadLocation, + } +} + // Label is used to represent a Bazel compatible Label. Also stores the original bp text to support // string replacement. type Label struct { diff --git a/bp2build/Android.bp b/bp2build/Android.bp index 2bbe4b53c..fdac88dfd 100644 --- a/bp2build/Android.bp +++ b/bp2build/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-bp2build", pkgPath: "android/soong/bp2build", @@ -12,6 +16,7 @@ bootstrap_go_package { "soong-android", "soong-bazel", "soong-genrule", + "soong-sh", ], testSrcs: [ "build_conversion_test.go", diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go index 2c293eae7..7ffcfa4a3 100644 --- a/bp2build/build_conversion.go +++ b/bp2build/build_conversion.go @@ -173,6 +173,12 @@ func GenerateBazelTargets(ctx bpToBuildContext, codegenMode CodegenMode) map[str } t = generateBazelTarget(ctx, m) case QueryView: + // Blocklist certain module types from being generated. + if canonicalizeModuleType(ctx.ModuleType(m)) == "package" { + // package module name contain slashes, and thus cannot + // be mapped cleanly to a bazel label. + return + } t = generateSoongModuleTarget(ctx, m) default: panic(fmt.Errorf("Unknown code-generation mode: %s", codegenMode)) @@ -213,6 +219,8 @@ func generateBazelTarget(ctx bpToBuildContext, m blueprint.Module) BazelTarget { // Delete it from being generated in the BUILD file. delete(props.Attrs, "bzl_load_location") + delete(props.Attrs, "bp2build_available") + // Return the Bazel target with rule class and attributes, ready to be // code-generated. attributes := propsToAttributes(props.Attrs) @@ -461,7 +469,7 @@ func makeIndent(indent int) string { } func targetNameForBp2Build(c bpToBuildContext, logicModule blueprint.Module) string { - return strings.Replace(c.ModuleName(logicModule), "__bp2build__", "", 1) + return strings.Replace(c.ModuleName(logicModule), bazel.BazelTargetModuleNamePrefix, "", 1) } func targetNameWithVariant(c bpToBuildContext, logicModule blueprint.Module) string { diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go index 081b0e564..df554a09a 100644 --- a/bp2build/build_conversion_test.go +++ b/bp2build/build_conversion_test.go @@ -17,6 +17,7 @@ package bp2build import ( "android/soong/android" "android/soong/genrule" + "android/soong/sh" "strings" "testing" ) @@ -228,6 +229,7 @@ func TestGenerateBazelTargetModules(t *testing.T) { name: "foo", string_list_prop: ["a", "b"], string_prop: "a", + bazel_module: { bp2build_available: true }, }`, expectedBazelTarget: `custom( name = "foo", @@ -356,6 +358,12 @@ load("//build/bazel/rules:java.bzl", "java_binary")`, ruleClass: "genrule", // Note: no bzlLoadLocation for native rules }, + BazelTarget{ + name: "sh_binary_target", + ruleClass: "sh_binary", + // Note: no bzlLoadLocation for native rules + // TODO(ruperts): Could open source the existing, experimental Starlark sh_ rules? + }, }, expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_binary") load("//build/bazel/rules:java.bzl", "java_binary")`, @@ -382,6 +390,7 @@ func TestGenerateBazelTargetModules_OneToMany_LoadedFromStarlark(t *testing.T) { { bp: `custom { name: "bar", + bazel_module: { bp2build_available: true }, }`, expectedBazelTarget: `my_library( name = "bar", @@ -474,6 +483,7 @@ genrule { bp: `filegroup { name: "fg_foo", srcs: [], + bazel_module: { bp2build_available: true }, }`, expectedBazelTargets: []string{ `filegroup( @@ -491,6 +501,7 @@ genrule { bp: `filegroup { name: "fg_foo", srcs: ["a", "b"], + bazel_module: { bp2build_available: true }, }`, expectedBazelTargets: []string{`filegroup( name = "fg_foo", @@ -510,6 +521,7 @@ genrule { name: "fg_foo", srcs: ["a", "b"], exclude_srcs: ["a"], + bazel_module: { bp2build_available: true }, }`, expectedBazelTargets: []string{`filegroup( name = "fg_foo", @@ -527,6 +539,7 @@ genrule { bp: `filegroup { name: "foo", srcs: ["**/*.txt"], + bazel_module: { bp2build_available: true }, }`, expectedBazelTargets: []string{`filegroup( name = "foo", @@ -552,6 +565,7 @@ genrule { bp: `filegroup { name: "foo", srcs: ["a.txt"], + bazel_module: { bp2build_available: true }, }`, dir: "other", expectedBazelTargets: []string{`filegroup( @@ -567,6 +581,7 @@ genrule { "other/Android.bp": `filegroup { name: "fg_foo", srcs: ["**/*.txt"], + bazel_module: { bp2build_available: true }, }`, "other/a.txt": "", "other/b.txt": "", @@ -585,6 +600,7 @@ genrule { ":foo", "c", ], + bazel_module: { bp2build_available: true }, }`, expectedBazelTargets: []string{`filegroup( name = "foobar", @@ -612,6 +628,7 @@ genrule { out: ["foo_tool.out"], srcs: ["foo_tool.in"], cmd: "cp $(in) $(out)", + bazel_module: { bp2build_available: true }, } genrule { @@ -620,6 +637,7 @@ genrule { srcs: ["foo.in"], tools: [":foo.tool"], cmd: "$(location :foo.tool) --genDir=$(genDir) arg $(in) $(out)", + bazel_module: { bp2build_available: true }, }`, expectedBazelTargets: []string{ `genrule( @@ -658,7 +676,8 @@ genrule { out: ["foo_tool.out", "foo_tool2.out"], srcs: ["foo_tool.in"], cmd: "cp $(in) $(out)", - } + bazel_module: { bp2build_available: true }, +} genrule { name: "foo", @@ -666,6 +685,7 @@ genrule { srcs: ["foo.in"], tools: [":foo.tools"], cmd: "$(locations :foo.tools) -s $(out) $(in)", + bazel_module: { bp2build_available: true }, }`, expectedBazelTargets: []string{`genrule( name = "foo", @@ -705,6 +725,7 @@ genrule { srcs: ["foo.in"], tool_files: [":foo.tool"], cmd: "$(locations :foo.tool) -s $(out) $(in)", + bazel_module: { bp2build_available: true }, }`, expectedBazelTargets: []string{`genrule( name = "foo", @@ -734,6 +755,7 @@ genrule { srcs: [":other.tool"], tool_files: [":foo.tool"], cmd: "$(locations :foo.tool) -s $(out) $(location :other.tool)", + bazel_module: { bp2build_available: true }, }`, expectedBazelTargets: []string{`genrule( name = "foo", @@ -763,6 +785,7 @@ genrule { srcs: ["foo.in"], tool_files: [":foo.tool", ":other.tool"], cmd: "$(location) -s $(out) $(in)", + bazel_module: { bp2build_available: true }, }`, expectedBazelTargets: []string{`genrule( name = "foo", @@ -793,6 +816,7 @@ genrule { srcs: ["foo.in"], tools: [":foo.tool", ":other.tool"], cmd: "$(locations) -s $(out) $(in)", + bazel_module: { bp2build_available: true }, }`, expectedBazelTargets: []string{`genrule( name = "foo", @@ -822,6 +846,7 @@ genrule { out: ["foo.out"], srcs: ["foo.in"], cmd: "cp $(in) $(out)", + bazel_module: { bp2build_available: true }, }`, expectedBazelTargets: []string{`genrule( name = "foo", @@ -835,6 +860,23 @@ genrule { )`, }, }, + { + description: "sh_binary test", + moduleTypeUnderTest: "sh_binary", + moduleTypeUnderTestFactory: sh.ShBinaryFactory, + moduleTypeUnderTestBp2BuildMutator: sh.ShBinaryBp2Build, + bp: `sh_binary { + name: "foo", + src: "foo.sh", + bazel_module: { bp2build_available: true }, +}`, + expectedBazelTargets: []string{`sh_binary( + name = "foo", + srcs = [ + "foo.sh", + ], +)`}, + }, } dir := "." @@ -927,6 +969,7 @@ genrule { out: ["out"], srcs: ["in1"], defaults: ["gen_defaults"], + bazel_module: { bp2build_available: true }, } `, expectedBazelTarget: `genrule( @@ -961,6 +1004,7 @@ genrule { srcs: ["in1"], defaults: ["gen_defaults"], cmd: "do-something $(in) $(out)", + bazel_module: { bp2build_available: true }, } `, expectedBazelTarget: `genrule( @@ -999,6 +1043,7 @@ genrule { name: "gen", out: ["out"], defaults: ["gen_defaults1", "gen_defaults2"], + bazel_module: { bp2build_available: true }, } `, expectedBazelTarget: `genrule( @@ -1045,6 +1090,7 @@ genrule { name: "gen", out: ["out"], defaults: ["gen_defaults1"], + bazel_module: { bp2build_available: true }, } `, expectedBazelTarget: `genrule( @@ -1097,3 +1143,80 @@ genrule { } } } + +func TestAllowlistingBp2buildTargets(t *testing.T) { + testCases := []struct { + moduleTypeUnderTest string + moduleTypeUnderTestFactory android.ModuleFactory + moduleTypeUnderTestBp2BuildMutator bp2buildMutator + bp string + expectedCount int + description string + }{ + { + description: "explicitly unavailable", + moduleTypeUnderTest: "filegroup", + moduleTypeUnderTestFactory: android.FileGroupFactory, + moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build, + bp: `filegroup { + name: "foo", + srcs: ["a", "b"], + bazel_module: { bp2build_available: false }, +}`, + expectedCount: 0, + }, + { + description: "implicitly unavailable", + moduleTypeUnderTest: "filegroup", + moduleTypeUnderTestFactory: android.FileGroupFactory, + moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build, + bp: `filegroup { + name: "foo", + srcs: ["a", "b"], +}`, + expectedCount: 0, + }, + { + description: "explicitly available", + moduleTypeUnderTest: "filegroup", + moduleTypeUnderTestFactory: android.FileGroupFactory, + moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build, + bp: `filegroup { + name: "foo", + srcs: ["a", "b"], + bazel_module: { bp2build_available: true }, +}`, + expectedCount: 1, + }, + { + description: "generates more than 1 target if needed", + moduleTypeUnderTest: "custom", + moduleTypeUnderTestFactory: customModuleFactory, + moduleTypeUnderTestBp2BuildMutator: customBp2BuildMutatorFromStarlark, + bp: `custom { + name: "foo", + bazel_module: { bp2build_available: true }, +}`, + expectedCount: 3, + }, + } + + dir := "." + for _, testCase := range testCases { + config := android.TestConfig(buildDir, nil, testCase.bp, nil) + ctx := android.NewTestContext(config) + ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory) + ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator) + ctx.RegisterForBazelConversion() + + _, errs := ctx.ParseFileList(dir, []string{"Android.bp"}) + android.FailIfErrored(t, errs) + _, errs = ctx.ResolveDependencies(config) + android.FailIfErrored(t, errs) + + bazelTargets := GenerateBazelTargets(ctx.Context.Context, Bp2Build)[dir] + if actualCount := len(bazelTargets); actualCount != testCase.expectedCount { + t.Fatalf("%s: Expected %d bazel target, got %d", testCase.description, testCase.expectedCount, actualCount) + } + } +} diff --git a/bp2build/bzl_conversion_test.go b/bp2build/bzl_conversion_test.go index f2a405854..30c1a5b6a 100644 --- a/bp2build/bzl_conversion_test.go +++ b/bp2build/bzl_conversion_test.go @@ -86,6 +86,10 @@ custom = rule( "soong_module_name": attr.string(mandatory = True), "soong_module_variant": attr.string(), "soong_module_deps": attr.label_list(providers = [SoongModuleInfo]), + # bazel_module start +# "label": attr.string(), +# "bp2build_available": attr.bool(), + # bazel_module end "bool_prop": attr.bool(), "bool_ptr_prop": attr.bool(), "int64_ptr_prop": attr.int(), diff --git a/bp2build/conversion.go b/bp2build/conversion.go index 62cd8d4b6..081e08243 100644 --- a/bp2build/conversion.go +++ b/bp2build/conversion.go @@ -50,14 +50,19 @@ func createBuildFiles(buildToTargets map[string]BazelTargets, mode CodegenMode) sort.Slice(targets, func(i, j int) bool { return targets[i].name < targets[j].name }) content := soongModuleLoad if mode == Bp2Build { - content = targets.LoadStatements() + content = `# This file was automatically generated by bp2build for the Bazel migration project. +# Feel free to edit or test it, but do *not* check it into your version control system.` + content += "\n\n" + content += "package(default_visibility = [\"//visibility:public\"])" + content += "\n\n" + content += targets.LoadStatements() } if content != "" { // If there are load statements, add a couple of newlines. content += "\n\n" } content += targets.String() - files = append(files, newFile(dir, "BUILD.bazel", content)) + files = append(files, newFile(dir, "BUILD", content)) } return files } diff --git a/bp2build/testing.go b/bp2build/testing.go index 5e6481b32..2e59999c2 100644 --- a/bp2build/testing.go +++ b/bp2build/testing.go @@ -3,8 +3,6 @@ package bp2build import ( "android/soong/android" "android/soong/bazel" - - "github.com/google/blueprint/proptools" ) type nestedProps struct { @@ -29,6 +27,8 @@ type customModule struct { android.ModuleBase props customProps + + bazelProps bazel.Properties } // OutputFiles is needed because some instances of this module use dist with a @@ -44,6 +44,7 @@ func (m *customModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { func customModuleFactoryBase() android.Module { module := &customModule{} module.AddProperties(&module.props) + module.AddProperties(&module.bazelProps) return module } @@ -105,7 +106,6 @@ func customDefaultsModuleFactory() android.Module { } type customBazelModuleAttributes struct { - Name *string String_prop string String_list_prop []string } @@ -127,14 +127,18 @@ func (m *customBazelModule) GenerateAndroidBuildActions(ctx android.ModuleContex func customBp2BuildMutator(ctx android.TopDownMutatorContext) { if m, ok := ctx.Module().(*customModule); ok { - name := "__bp2build__" + m.Name() - ctx.CreateModule(customBazelModuleFactory, &customBazelModuleAttributes{ - Name: proptools.StringPtr(name), + if !m.bazelProps.Bazel_module.Bp2build_available { + return + } + + attrs := &customBazelModuleAttributes{ String_prop: m.props.String_prop, String_list_prop: m.props.String_list_prop, - }, &bazel.BazelTargetModuleProperties{ - Rule_class: "custom", - }) + } + + props := bazel.NewBazelTargetModuleProperties(m.Name(), "custom", "") + + ctx.CreateBazelTargetModule(customBazelModuleFactory, props, attrs) } } @@ -142,24 +146,32 @@ func customBp2BuildMutator(ctx android.TopDownMutatorContext) { // module to target. func customBp2BuildMutatorFromStarlark(ctx android.TopDownMutatorContext) { if m, ok := ctx.Module().(*customModule); ok { - baseName := "__bp2build__" + m.Name() - ctx.CreateModule(customBazelModuleFactory, &customBazelModuleAttributes{ - Name: proptools.StringPtr(baseName), - }, &bazel.BazelTargetModuleProperties{ - Rule_class: "my_library", - Bzl_load_location: "//build/bazel/rules:rules.bzl", - }) - ctx.CreateModule(customBazelModuleFactory, &customBazelModuleAttributes{ - Name: proptools.StringPtr(baseName + "_proto_library_deps"), - }, &bazel.BazelTargetModuleProperties{ - Rule_class: "proto_library", - Bzl_load_location: "//build/bazel/rules:proto.bzl", - }) - ctx.CreateModule(customBazelModuleFactory, &customBazelModuleAttributes{ - Name: proptools.StringPtr(baseName + "_my_proto_library_deps"), - }, &bazel.BazelTargetModuleProperties{ - Rule_class: "my_proto_library", - Bzl_load_location: "//build/bazel/rules:proto.bzl", - }) + if !m.bazelProps.Bazel_module.Bp2build_available { + return + } + + baseName := m.Name() + attrs := &customBazelModuleAttributes{} + + myLibraryProps := bazel.NewBazelTargetModuleProperties( + baseName, + "my_library", + "//build/bazel/rules:rules.bzl", + ) + ctx.CreateBazelTargetModule(customBazelModuleFactory, myLibraryProps, attrs) + + protoLibraryProps := bazel.NewBazelTargetModuleProperties( + baseName+"_proto_library_deps", + "proto_library", + "//build/bazel/rules:proto.bzl", + ) + ctx.CreateBazelTargetModule(customBazelModuleFactory, protoLibraryProps, attrs) + + myProtoLibraryProps := bazel.NewBazelTargetModuleProperties( + baseName+"_my_proto_library_deps", + "my_proto_library", + "//build/bazel/rules:proto.bzl", + ) + ctx.CreateBazelTargetModule(customBazelModuleFactory, myProtoLibraryProps, attrs) } } diff --git a/bpf/Android.bp b/bpf/Android.bp index 882cd8afe..3ffa29f58 100644 --- a/bpf/Android.bp +++ b/bpf/Android.bp @@ -14,6 +14,10 @@ // limitations under the License. // +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-bpf", pkgPath: "android/soong/bpf", diff --git a/bpfix/Android.bp b/bpfix/Android.bp index b244e3abb..345dbd078 100644 --- a/bpfix/Android.bp +++ b/bpfix/Android.bp @@ -16,6 +16,10 @@ // androidmk Android.mk to Blueprints translator // +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + blueprint_go_binary { name: "bpfix", srcs: [ diff --git a/cc/Android.bp b/cc/Android.bp index 6ec7e0ee7..bdbb3c0b4 100644 --- a/cc/Android.bp +++ b/cc/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-cc", pkgPath: "android/soong/cc", diff --git a/cc/androidmk.go b/cc/androidmk.go index ddb81d99b..8652c1042 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -26,9 +26,9 @@ import ( var ( nativeBridgeSuffix = ".native_bridge" productSuffix = ".product" - vendorSuffix = ".vendor" + VendorSuffix = ".vendor" ramdiskSuffix = ".ramdisk" - vendorRamdiskSuffix = ".vendor_ramdisk" + VendorRamdiskSuffix = ".vendor_ramdisk" recoverySuffix = ".recovery" sdkSuffix = ".sdk" ) @@ -1544,7 +1544,7 @@ func (c *Module) getNameSuffixWithVndkVersion(ctx android.ModuleContext) string nameSuffix = productSuffix } else { vndkVersion = ctx.DeviceConfig().VndkVersion() - nameSuffix = vendorSuffix + nameSuffix = VendorSuffix } if vndkVersion == "current" { vndkVersion = ctx.DeviceConfig().PlatformVndkVersion() @@ -1591,11 +1591,11 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { } else if _, ok := c.linker.(*vndkPrebuiltLibraryDecorator); ok { // .vendor suffix is added for backward compatibility with VNDK snapshot whose names with // such suffixes are already hard-coded in prebuilts/vndk/.../Android.bp. - c.Properties.SubName += vendorSuffix + c.Properties.SubName += VendorSuffix } else if c.InRamdisk() && !c.OnlyInRamdisk() { c.Properties.SubName += ramdiskSuffix } else if c.InVendorRamdisk() && !c.OnlyInVendorRamdisk() { - c.Properties.SubName += vendorRamdiskSuffix + c.Properties.SubName += VendorRamdiskSuffix } else if c.InRecovery() && !c.OnlyInRecovery() { c.Properties.SubName += recoverySuffix } else if c.IsSdkVariant() && (c.Properties.SdkAndPlatformVariantVisibleToMake || c.SplitPerApiLevel()) { @@ -2927,7 +2927,7 @@ func (c *Module) makeLibName(ctx android.ModuleContext, ccDep LinkableInterface, } else if ccDep.InRamdisk() && !ccDep.OnlyInRamdisk() { return libName + ramdiskSuffix } else if ccDep.InVendorRamdisk() && !ccDep.OnlyInVendorRamdisk() { - return libName + vendorRamdiskSuffix + return libName + VendorRamdiskSuffix } else if ccDep.InRecovery() && !ccDep.OnlyInRecovery() { return libName + recoverySuffix } else if ccDep.Target().NativeBridge == android.NativeBridgeEnabled { diff --git a/cc/config/Android.bp b/cc/config/Android.bp index ce4bdfb50..5ef247df9 100644 --- a/cc/config/Android.bp +++ b/cc/config/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-cc-config", pkgPath: "android/soong/cc/config", diff --git a/cc/config/vndk.go b/cc/config/vndk.go index 45c18c2f4..425e3499d 100644 --- a/cc/config/vndk.go +++ b/cc/config/vndk.go @@ -41,6 +41,9 @@ var VndkMustUseVendorVariantList = []string{ "android.hardware.power-V1-ndk_platform", "android.hardware.power-ndk_platform", "android.hardware.rebootescrow-V1-ndk_platform", + "android.hardware.power.stats-V1-ndk_platform", + "android.hardware.power.stats-ndk_platform", + "android.hardware.power.stats-unstable-ndk_platform", "android.hardware.rebootescrow-ndk_platform", "android.hardware.security.keymint-V1-ndk_platform", "android.hardware.security.keymint-ndk_platform", diff --git a/cc/libbuildversion/Android.bp b/cc/libbuildversion/Android.bp index b63338da3..4debb1c45 100644 --- a/cc/libbuildversion/Android.bp +++ b/cc/libbuildversion/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + cc_library_static { name: "libbuildversion", host_supported: true, diff --git a/cc/libbuildversion/tests/Android.bp b/cc/libbuildversion/tests/Android.bp index b3b206159..0e97fedff 100644 --- a/cc/libbuildversion/tests/Android.bp +++ b/cc/libbuildversion/tests/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + cc_defaults { name: "build_version_test_defaults", use_version_lib: true, diff --git a/cc/library.go b/cc/library.go index f185cb793..65533bc2b 100644 --- a/cc/library.go +++ b/cc/library.go @@ -648,6 +648,11 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa return objs } if library.buildStubs() { + symbolFile := String(library.Properties.Stubs.Symbol_file) + if symbolFile != "" && !strings.HasSuffix(symbolFile, ".map.txt") { + ctx.PropertyErrorf("symbol_file", "%q doesn't have .map.txt suffix", symbolFile) + return Objects{} + } objs, versionScript := compileStubLibrary(ctx, flags, String(library.Properties.Stubs.Symbol_file), library.MutatedProperties.StubsVersion, "--apex") library.versionScriptPath = android.OptionalPathForPath(versionScript) return objs diff --git a/cc/ndk_api_coverage_parser/Android.bp b/cc/ndk_api_coverage_parser/Android.bp index 8d9827ca6..b119e9065 100644 --- a/cc/ndk_api_coverage_parser/Android.bp +++ b/cc/ndk_api_coverage_parser/Android.bp @@ -14,6 +14,10 @@ // limitations under the License. // +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + python_library_host { name: "ndk_api_coverage_parser_lib", pkg_path: "ndk_api_coverage_parser", diff --git a/cc/ndkstubgen/Android.bp b/cc/ndkstubgen/Android.bp index 85dfaee18..782c12469 100644 --- a/cc/ndkstubgen/Android.bp +++ b/cc/ndkstubgen/Android.bp @@ -14,6 +14,10 @@ // limitations under the License. // +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + python_binary_host { name: "ndkstubgen", pkg_path: "ndkstubgen", diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go index ffaed8e55..62daafde4 100644 --- a/cc/snapshot_prebuilt.go +++ b/cc/snapshot_prebuilt.go @@ -144,7 +144,7 @@ func (vendorSnapshotImage) imageVariantName(cfg android.DeviceConfig) string { } func (vendorSnapshotImage) moduleNameSuffix() string { - return vendorSuffix + return VendorSuffix } func (recoverySnapshotImage) init(ctx android.RegistrationContext) { @@ -195,8 +195,12 @@ func (recoverySnapshotImage) targetSnapshotVersion(cfg android.DeviceConfig) str } func (recoverySnapshotImage) excludeFromDirectedSnapshot(cfg android.DeviceConfig, name string) bool { - // directed recovery snapshot is not implemented yet - return false + // If we're using full snapshot, not directed snapshot, capture every module + if !cfg.DirectedRecoverySnapshot() { + return false + } + // Else, checks if name is in RECOVERY_SNAPSHOT_MODULES. + return !cfg.RecoverySnapshotModules()[name] } func (recoverySnapshotImage) imageVariantName(cfg android.DeviceConfig) string { diff --git a/cc/symbolfile/Android.bp b/cc/symbolfile/Android.bp index 5b4330916..6722110da 100644 --- a/cc/symbolfile/Android.bp +++ b/cc/symbolfile/Android.bp @@ -14,6 +14,10 @@ // limitations under the License. // +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + python_library_host { name: "symbolfile", pkg_path: "symbolfile", diff --git a/cc/testing.go b/cc/testing.go index 3a5bd1762..45e531208 100644 --- a/cc/testing.go +++ b/cc/testing.go @@ -43,6 +43,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { name: "libatomic", defaults: ["linux_bionic_supported"], vendor_available: true, + vendor_ramdisk_available: true, product_available: true, recovery_available: true, native_bridge_supported: true, @@ -52,6 +53,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { toolchain_library { name: "libcompiler_rt-extras", vendor_available: true, + vendor_ramdisk_available: true, product_available: true, recovery_available: true, src: "", @@ -60,6 +62,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { toolchain_library { name: "libclang_rt.builtins-arm-android", vendor_available: true, + vendor_ramdisk_available: true, product_available: true, recovery_available: true, native_bridge_supported: true, @@ -69,6 +72,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { toolchain_library { name: "libclang_rt.builtins-aarch64-android", vendor_available: true, + vendor_ramdisk_available: true, product_available: true, recovery_available: true, native_bridge_supported: true, @@ -93,6 +97,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { toolchain_library { name: "libclang_rt.builtins-i686-android", vendor_available: true, + vendor_ramdisk_available: true, product_available: true, recovery_available: true, native_bridge_supported: true, @@ -103,6 +108,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { name: "libclang_rt.builtins-x86_64-android", defaults: ["linux_bionic_supported"], vendor_available: true, + vendor_ramdisk_available: true, product_available: true, recovery_available: true, native_bridge_supported: true, @@ -113,6 +119,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { name: "libunwind", defaults: ["linux_bionic_supported"], vendor_available: true, + vendor_ramdisk_available: true, product_available: true, recovery_available: true, native_bridge_supported: true, @@ -238,6 +245,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { cc_library { name: "libprofile-extras", vendor_available: true, + vendor_ramdisk_available: true, product_available: true, recovery_available: true, native_coverage: false, @@ -248,6 +256,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { cc_library { name: "libprofile-clang-extras", vendor_available: true, + vendor_ramdisk_available: true, product_available: true, recovery_available: true, native_coverage: false, @@ -319,6 +328,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { system_shared_libs: [], stl: "none", vendor_available: true, + vendor_ramdisk_available: true, product_available: true, recovery_available: true, host_supported: true, @@ -356,6 +366,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { stl: "none", host_supported: false, vendor_available: true, + vendor_ramdisk_available: true, product_available: true, recovery_available: true, min_sdk_version: "29", @@ -380,6 +391,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { defaults: ["linux_bionic_supported"], recovery_available: true, vendor_available: true, + vendor_ramdisk_available: true, product_available: true, native_bridge_supported: true, stl: "none", diff --git a/cc/vendor_snapshot_test.go b/cc/vendor_snapshot_test.go index 659b6931c..7e283fb89 100644 --- a/cc/vendor_snapshot_test.go +++ b/cc/vendor_snapshot_test.go @@ -1051,3 +1051,85 @@ func TestRecoverySnapshotExclude(t *testing.T) { } } } + +func TestRecoverySnapshotDirected(t *testing.T) { + bp := ` + cc_library_shared { + name: "librecovery", + recovery: true, + nocrt: true, + } + + cc_library_shared { + name: "librecovery_available", + recovery_available: true, + nocrt: true, + } + + genrule { + name: "libfoo_gen", + cmd: "", + out: ["libfoo.so"], + } + + cc_prebuilt_library_shared { + name: "libfoo", + recovery: true, + prefer: true, + srcs: [":libfoo_gen"], + } + + cc_library_shared { + name: "libfoo", + recovery: true, + nocrt: true, + } +` + config := TestConfig(buildDir, android.Android, nil, bp, nil) + config.TestProductVariables.DeviceVndkVersion = StringPtr("current") + config.TestProductVariables.RecoverySnapshotVersion = StringPtr("current") + config.TestProductVariables.Platform_vndk_version = StringPtr("VER") + config.TestProductVariables.DirectedRecoverySnapshot = true + config.TestProductVariables.RecoverySnapshotModules = make(map[string]bool) + config.TestProductVariables.RecoverySnapshotModules["librecovery"] = true + config.TestProductVariables.RecoverySnapshotModules["libfoo"] = true + ctx := testCcWithConfig(t, config) + + // Check recovery snapshot output. + + snapshotDir := "recovery-snapshot" + snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64") + snapshotSingleton := ctx.SingletonForTests("recovery-snapshot") + + var includeJsonFiles []string + + for _, arch := range [][]string{ + []string{"arm64", "armv8-a"}, + } { + archType := arch[0] + archVariant := arch[1] + archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant) + + sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant) + sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") + + // Included modules + checkSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "librecovery.so.json")) + // Check that snapshot captures "prefer: true" prebuilt + checkSnapshot(t, ctx, snapshotSingleton, "prebuilt_libfoo", "libfoo.so", sharedDir, sharedVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libfoo.so.json")) + + // Excluded modules. Modules not included in the directed recovery snapshot + // are still include as fake modules. + checkSnapshotRule(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.so", sharedDir, sharedVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "librecovery_available.so.json")) + } + + // Verify that each json file for an included module has a rule. + for _, jsonFile := range includeJsonFiles { + if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil { + t.Errorf("include json file %q not found", jsonFile) + } + } +} diff --git a/cmd/dep_fixer/Android.bp b/cmd/dep_fixer/Android.bp index 97364d58b..818fd2854 100644 --- a/cmd/dep_fixer/Android.bp +++ b/cmd/dep_fixer/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + blueprint_go_binary { name: "dep_fixer", deps: ["soong-makedeps"], diff --git a/cmd/diff_target_files/Android.bp b/cmd/diff_target_files/Android.bp index bc6b068b9..ae8c329fc 100644 --- a/cmd/diff_target_files/Android.bp +++ b/cmd/diff_target_files/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + blueprint_go_binary { name: "diff_target_files", srcs: [ diff --git a/cmd/extract_apks/Android.bp b/cmd/extract_apks/Android.bp index f8fe864a9..8a4ed6396 100644 --- a/cmd/extract_apks/Android.bp +++ b/cmd/extract_apks/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + blueprint_go_binary { name: "extract_apks", srcs: ["main.go"], diff --git a/cmd/extract_jar_packages/Android.bp b/cmd/extract_jar_packages/Android.bp index 4ea879834..ab33504d8 100644 --- a/cmd/extract_jar_packages/Android.bp +++ b/cmd/extract_jar_packages/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + blueprint_go_binary { name: "extract_jar_packages", deps: [ diff --git a/cmd/extract_linker/Android.bp b/cmd/extract_linker/Android.bp index 690c4fa41..d40d250bb 100644 --- a/cmd/extract_linker/Android.bp +++ b/cmd/extract_linker/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + blueprint_go_binary { name: "extract_linker", srcs: ["main.go"], diff --git a/cmd/fileslist/Android.bp b/cmd/fileslist/Android.bp index cbf939a19..3c6f675f2 100644 --- a/cmd/fileslist/Android.bp +++ b/cmd/fileslist/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + blueprint_go_binary { name: "fileslist", srcs: [ diff --git a/cmd/host_bionic_inject/Android.bp b/cmd/host_bionic_inject/Android.bp index 599410320..16bc1793c 100644 --- a/cmd/host_bionic_inject/Android.bp +++ b/cmd/host_bionic_inject/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + blueprint_go_binary { name: "host_bionic_inject", deps: ["soong-symbol_inject"], diff --git a/cmd/javac_wrapper/Android.bp b/cmd/javac_wrapper/Android.bp index c00f4bd16..e441567e2 100644 --- a/cmd/javac_wrapper/Android.bp +++ b/cmd/javac_wrapper/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + blueprint_go_binary { name: "soong_javac_wrapper", srcs: [ diff --git a/cmd/merge_zips/Android.bp b/cmd/merge_zips/Android.bp index 8c97b6dfe..930d040f4 100644 --- a/cmd/merge_zips/Android.bp +++ b/cmd/merge_zips/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + blueprint_go_binary { name: "merge_zips", deps: [ diff --git a/cmd/multiproduct_kati/Android.bp b/cmd/multiproduct_kati/Android.bp index d34f8c3c1..21d8e21f2 100644 --- a/cmd/multiproduct_kati/Android.bp +++ b/cmd/multiproduct_kati/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + blueprint_go_binary { name: "multiproduct_kati", deps: [ diff --git a/cmd/path_interposer/Android.bp b/cmd/path_interposer/Android.bp index 41a219f9c..875cd7236 100644 --- a/cmd/path_interposer/Android.bp +++ b/cmd/path_interposer/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + blueprint_go_binary { name: "path_interposer", deps: ["soong-ui-build-paths"], diff --git a/cmd/pom2bp/Android.bp b/cmd/pom2bp/Android.bp index 0b2b7b5dd..0dfed8bd5 100644 --- a/cmd/pom2bp/Android.bp +++ b/cmd/pom2bp/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + blueprint_go_binary { name: "pom2bp", deps: [ diff --git a/cmd/pom2mk/Android.bp b/cmd/pom2mk/Android.bp index 54422b165..cc9daccd7 100644 --- a/cmd/pom2mk/Android.bp +++ b/cmd/pom2mk/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + blueprint_go_binary { name: "pom2mk", deps: ["blueprint-proptools"], diff --git a/cmd/sbox/Android.bp b/cmd/sbox/Android.bp index f5e87c0c2..d88505fcc 100644 --- a/cmd/sbox/Android.bp +++ b/cmd/sbox/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + blueprint_go_binary { name: "sbox", deps: [ diff --git a/cmd/soong_build/Android.bp b/cmd/soong_build/Android.bp index 671497898..6a0a87bc6 100644 --- a/cmd/soong_build/Android.bp +++ b/cmd/soong_build/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_binary { name: "soong_build", deps: [ diff --git a/cmd/soong_env/Android.bp b/cmd/soong_env/Android.bp index 4db0da303..ad717d0b1 100644 --- a/cmd/soong_env/Android.bp +++ b/cmd/soong_env/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_binary { name: "soong_env", deps: [ diff --git a/cmd/soong_ui/Android.bp b/cmd/soong_ui/Android.bp index 4e57bef38..4f5eea900 100644 --- a/cmd/soong_ui/Android.bp +++ b/cmd/soong_ui/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + blueprint_go_binary { name: "soong_ui", deps: [ diff --git a/cmd/zip2zip/Android.bp b/cmd/zip2zip/Android.bp index 2c4cd82dd..3ef766865 100644 --- a/cmd/zip2zip/Android.bp +++ b/cmd/zip2zip/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + blueprint_go_binary { name: "zip2zip", deps: [ diff --git a/cmd/zipsync/Android.bp b/cmd/zipsync/Android.bp index 49b5f3ecd..0dcdd5c8f 100644 --- a/cmd/zipsync/Android.bp +++ b/cmd/zipsync/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + blueprint_go_binary { name: "zipsync", deps: [ diff --git a/cuj/Android.bp b/cuj/Android.bp index 21d667f3c..a2da6e68e 100644 --- a/cuj/Android.bp +++ b/cuj/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + blueprint_go_binary { name: "cuj_tests", deps: [ diff --git a/dexpreopt/Android.bp b/dexpreopt/Android.bp index 35f90df68..679d06627 100644 --- a/dexpreopt/Android.bp +++ b/dexpreopt/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-dexpreopt", pkgPath: "android/soong/dexpreopt", diff --git a/dexpreopt/class_loader_context.go b/dexpreopt/class_loader_context.go index ec62eb3d8..ad52b00c4 100644 --- a/dexpreopt/class_loader_context.go +++ b/dexpreopt/class_loader_context.go @@ -489,20 +489,16 @@ func computeClassLoaderContextRec(clcs []*ClassLoaderContext) (string, string, a } // Class loader contexts that come from Make via JSON dexpreopt.config. JSON CLC representation is -// slightly different: it uses a map of library names to their CLC (instead of a list of structs -// that including the name, as in the Soong CLC representation). The difference is insubstantial, it -// is caused only by the language differerences between Go and JSON. +// the same as Soong representation except that SDK versions and paths are represented with strings. type jsonClassLoaderContext struct { + Name string Host string Device string - Subcontexts map[string]*jsonClassLoaderContext + Subcontexts []*jsonClassLoaderContext } -// A map of <uses-library> name to its on-host and on-device build paths and CLC. -type jsonClassLoaderContexts map[string]*jsonClassLoaderContext - // A map from SDK version (represented with a JSON string) to JSON CLCs. -type jsonClassLoaderContextMap map[string]map[string]*jsonClassLoaderContext +type jsonClassLoaderContextMap map[string][]*jsonClassLoaderContext // Convert JSON CLC map to Soong represenation. func fromJsonClassLoaderContext(ctx android.PathContext, jClcMap jsonClassLoaderContextMap) ClassLoaderContextMap { @@ -522,11 +518,11 @@ func fromJsonClassLoaderContext(ctx android.PathContext, jClcMap jsonClassLoader } // Recursive helper for fromJsonClassLoaderContext. -func fromJsonClassLoaderContextRec(ctx android.PathContext, jClcs map[string]*jsonClassLoaderContext) []*ClassLoaderContext { +func fromJsonClassLoaderContextRec(ctx android.PathContext, jClcs []*jsonClassLoaderContext) []*ClassLoaderContext { clcs := make([]*ClassLoaderContext, 0, len(jClcs)) - for lib, clc := range jClcs { + for _, clc := range jClcs { clcs = append(clcs, &ClassLoaderContext{ - Name: lib, + Name: clc.Name, Host: constructPath(ctx, clc.Host), Device: clc.Device, Subcontexts: fromJsonClassLoaderContextRec(ctx, clc.Subcontexts), @@ -546,14 +542,15 @@ func toJsonClassLoaderContext(clcMap ClassLoaderContextMap) jsonClassLoaderConte } // Recursive helper for toJsonClassLoaderContext. -func toJsonClassLoaderContextRec(clcs []*ClassLoaderContext) map[string]*jsonClassLoaderContext { - jClcs := make(map[string]*jsonClassLoaderContext, len(clcs)) +func toJsonClassLoaderContextRec(clcs []*ClassLoaderContext) []*jsonClassLoaderContext { + jClcs := make([]*jsonClassLoaderContext, len(clcs)) for _, clc := range clcs { - jClcs[clc.Name] = &jsonClassLoaderContext{ + jClcs = append(jClcs, &jsonClassLoaderContext{ + Name: clc.Name, Host: clc.Host.String(), Device: clc.Device, Subcontexts: toJsonClassLoaderContextRec(clc.Subcontexts), - } + }) } return jClcs } diff --git a/dexpreopt/dexpreopt_gen/Android.bp b/dexpreopt/dexpreopt_gen/Android.bp index 3f0619cb6..2111451ab 100644 --- a/dexpreopt/dexpreopt_gen/Android.bp +++ b/dexpreopt/dexpreopt_gen/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + blueprint_go_binary { name: "dexpreopt_gen", srcs: [ diff --git a/env/Android.bp b/env/Android.bp index 90c604729..c6a97b1e6 100644 --- a/env/Android.bp +++ b/env/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-env", pkgPath: "android/soong/env", diff --git a/etc/Android.bp b/etc/Android.bp index cfd303ec8..cab7389b6 100644 --- a/etc/Android.bp +++ b/etc/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-etc", pkgPath: "android/soong/etc", diff --git a/filesystem/Android.bp b/filesystem/Android.bp index 999424109..42a4c88b5 100644 --- a/filesystem/Android.bp +++ b/filesystem/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-filesystem", pkgPath: "android/soong/filesystem", diff --git a/finder/Android.bp b/finder/Android.bp index a5d7fd4b0..a3df6ecfb 100644 --- a/finder/Android.bp +++ b/finder/Android.bp @@ -16,6 +16,10 @@ // fast, parallel, caching implementation of `find` // +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + subdirs = [ "cmd", ] diff --git a/finder/cmd/Android.bp b/finder/cmd/Android.bp index e066c39a1..32843a0d6 100644 --- a/finder/cmd/Android.bp +++ b/finder/cmd/Android.bp @@ -16,6 +16,10 @@ // fast, parallel, caching implementation of `find` // +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + blueprint_go_binary { name: "finder", srcs: [ diff --git a/finder/fs/Android.bp b/finder/fs/Android.bp index 85929aece..14bdb3020 100644 --- a/finder/fs/Android.bp +++ b/finder/fs/Android.bp @@ -16,6 +16,21 @@ // mock filesystem // +package { + default_applicable_licenses: [ + "Android-Apache-2.0", + "build_soong_finder_fs_license", + ], +} + +license { + name: "build_soong_finder_fs_license", + license_kinds: [ + "SPDX-license-identifier-BSD", + ], + license_text: ["LICENSE"], +} + bootstrap_go_package { name: "soong-finder-fs", pkgPath: "android/soong/finder/fs", diff --git a/finder/fs/LICENSE b/finder/fs/LICENSE new file mode 100644 index 000000000..e5c5bafb3 --- /dev/null +++ b/finder/fs/LICENSE @@ -0,0 +1,28 @@ +Copyright 2009, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of the Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/genrule/Android.bp b/genrule/Android.bp index 0e27d4e6c..214940d4f 100644 --- a/genrule/Android.bp +++ b/genrule/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-genrule", pkgPath: "android/soong/genrule", diff --git a/genrule/genrule.go b/genrule/genrule.go index 62aa7f834..9fa6c484f 100644 --- a/genrule/genrule.go +++ b/genrule/genrule.go @@ -780,7 +780,6 @@ type genRuleProperties struct { } type bazelGenruleAttributes struct { - Name *string Srcs bazel.LabelList Outs []string Tools bazel.LabelList @@ -801,10 +800,10 @@ func BazelGenruleFactory() android.Module { func GenruleBp2Build(ctx android.TopDownMutatorContext) { m, ok := ctx.Module().(*Module) - if !ok { + if !ok || !m.properties.Bazel_module.Bp2build_available { return } - name := "__bp2build__" + m.Name() + // Bazel only has the "tools" attribute. tools := android.BazelLabelForModuleDeps(ctx, m.properties.Tools) tool_files := android.BazelLabelForModuleSrc(ctx, m.properties.Tool_files) @@ -847,16 +846,17 @@ func GenruleBp2Build(ctx android.TopDownMutatorContext) { } } - // Create the BazelTargetModule. - ctx.CreateModule(BazelGenruleFactory, &bazelGenruleAttributes{ - Name: proptools.StringPtr(name), + attrs := &bazelGenruleAttributes{ Srcs: srcs, Outs: outs, Cmd: cmd, Tools: tools, - }, &bazel.BazelTargetModuleProperties{ - Rule_class: "genrule", - }) + } + + props := bazel.NewBazelTargetModuleProperties(m.Name(), "genrule", "") + + // Create the BazelTargetModule. + ctx.CreateBazelTargetModule(BazelGenruleFactory, props, attrs) } func (m *bazelGenrule) Name() string { diff --git a/jar/Android.bp b/jar/Android.bp index 2563474af..46113d877 100644 --- a/jar/Android.bp +++ b/jar/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-jar", pkgPath: "android/soong/jar", diff --git a/java/Android.bp b/java/Android.bp index 364566a8b..9bfd009c6 100644 --- a/java/Android.bp +++ b/java/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-java", pkgPath: "android/soong/java", diff --git a/java/aar.go b/java/aar.go index e3ad252fd..ac7ae2518 100644 --- a/java/aar.go +++ b/java/aar.go @@ -28,7 +28,6 @@ import ( ) type AndroidLibraryDependency interface { - Dependency ExportPackage() android.Path ExportedProguardFlagFiles() android.Paths ExportedRRODirs() []rroDir @@ -796,9 +795,13 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { aapt2Link(ctx, a.exportPackage, srcJar, proguardOptionsFile, rTxt, a.extraAaptPackagesFile, linkFlags, linkDeps, nil, overlayRes, transitiveAssets, nil) -} -var _ Dependency = (*AARImport)(nil) + ctx.SetProvider(JavaInfoProvider, JavaInfo{ + HeaderJars: android.PathsIfNonNil(a.classpathFile), + ImplementationAndResourcesJars: android.PathsIfNonNil(a.classpathFile), + ImplementationJars: android.PathsIfNonNil(a.classpathFile), + }) +} func (a *AARImport) HeaderJars() android.Paths { return android.Paths{a.classpathFile} diff --git a/java/androidmk.go b/java/androidmk.go index 21f3012a4..6e7c437ab 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -646,6 +646,9 @@ func (a *AndroidAppImport) AndroidMkEntries() []android.AndroidMkEntries { entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", a.dexpreopter.builtInstalled) } entries.AddStrings("LOCAL_INSTALLED_MODULE_STEM", a.installPath.Rel()) + if Bool(a.properties.Export_package_resources) { + entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", a.outputFile) + } }, }, }} diff --git a/java/app_import.go b/java/app_import.go index 6f21bfbbf..59eb10a9b 100644 --- a/java/app_import.go +++ b/java/app_import.go @@ -92,6 +92,10 @@ type AndroidAppImportProperties struct { // Optional name for the installed app. If unspecified, it is derived from the module name. Filename *string + + // If set, create package-export.apk, which other packages can + // use to get PRODUCT-agnostic resource data like IDs and type definitions. + Export_package_resources *bool } func (a *AndroidAppImport) IsInstallable() bool { @@ -142,13 +146,17 @@ func MergePropertiesFromVariant(ctx android.EarlyModuleContext, } } +func (a *AndroidAppImport) isPrebuiltFrameworkRes() bool { + return a.Name() == "prebuilt_framework-res" +} + func (a *AndroidAppImport) DepsMutator(ctx android.BottomUpMutatorContext) { cert := android.SrcIsModule(String(a.properties.Certificate)) if cert != "" { ctx.AddDependency(ctx.Module(), certificateTag, cert) } - a.usesLibrary.deps(ctx, true) + a.usesLibrary.deps(ctx, !a.isPrebuiltFrameworkRes()) } func (a *AndroidAppImport) uncompressEmbeddedJniLibs( @@ -247,7 +255,12 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext a.uncompressEmbeddedJniLibs(ctx, srcApk, jnisUncompressed.OutputPath) var installDir android.InstallPath - if Bool(a.properties.Privileged) { + + if a.isPrebuiltFrameworkRes() { + // framework-res.apk is installed as system/framework/framework-res.apk + installDir = android.PathForModuleInstall(ctx, "framework") + a.preprocessed = true + } else if Bool(a.properties.Privileged) { installDir = android.PathForModuleInstall(ctx, "priv-app", a.BaseModuleName()) } else if ctx.InstallInTestcases() { installDir = android.PathForModuleInstall(ctx, a.BaseModuleName(), ctx.DeviceConfig().DeviceArch()) @@ -275,7 +288,15 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext // TODO: Handle EXTERNAL // Sign or align the package if package has not been preprocessed - if a.preprocessed { + + if a.isPrebuiltFrameworkRes() { + a.outputFile = srcApk + certificates = processMainCert(a.ModuleBase, String(a.properties.Certificate), certificates, ctx) + if len(certificates) != 1 { + ctx.ModuleErrorf("Unexpected number of certificates were extracted: %q", certificates) + } + a.certificate = certificates[0] + } else if a.preprocessed { a.outputFile = srcApk a.certificate = PresignedCertificate } else if !Bool(a.properties.Presigned) { diff --git a/java/app_import_test.go b/java/app_import_test.go index 344d23b55..d7f69eb36 100644 --- a/java/app_import_test.go +++ b/java/app_import_test.go @@ -393,6 +393,69 @@ func TestAndroidAppImport_overridesDisabledAndroidApp(t *testing.T) { } } +func TestAndroidAppImport_frameworkRes(t *testing.T) { + ctx, config := testJava(t, ` + android_app_import { + name: "framework-res", + certificate: "platform", + apk: "package-res.apk", + prefer: true, + export_package_resources: true, + // Disable dexpreopt and verify_uses_libraries check as the app + // contains no Java code to be dexpreopted. + enforce_uses_libs: false, + dex_preopt: { + enabled: false, + }, + } + `) + + mod := ctx.ModuleForTests("prebuilt_framework-res", "android_common").Module() + a := mod.(*AndroidAppImport) + + if !a.preprocessed { + t.Errorf("prebuilt framework-res is not preprocessed") + } + + expectedInstallPath := buildDir + "/target/product/test_device/system/framework/framework-res.apk" + + if a.dexpreopter.installPath.String() != expectedInstallPath { + t.Errorf("prebuilt framework-res installed to incorrect location, actual: %s, expected: %s", a.dexpreopter.installPath, expectedInstallPath) + + } + + entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0] + + expectedPath := "." + // From apk property above, in the root of the source tree. + expectedPrebuiltModuleFile := "package-res.apk" + // Verify that the apk is preprocessed: The export package is the same + // as the prebuilt. + expectedSoongResourceExportPackage := expectedPrebuiltModuleFile + + actualPath := entries.EntryMap["LOCAL_PATH"] + actualPrebuiltModuleFile := entries.EntryMap["LOCAL_PREBUILT_MODULE_FILE"] + actualSoongResourceExportPackage := entries.EntryMap["LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE"] + + if len(actualPath) != 1 { + t.Errorf("LOCAL_PATH incorrect len %d", len(actualPath)) + } else if actualPath[0] != expectedPath { + t.Errorf("LOCAL_PATH mismatch, actual: %s, expected: %s", actualPath[0], expectedPath) + } + + if len(actualPrebuiltModuleFile) != 1 { + t.Errorf("LOCAL_PREBUILT_MODULE_FILE incorrect len %d", len(actualPrebuiltModuleFile)) + } else if actualPrebuiltModuleFile[0] != expectedPrebuiltModuleFile { + t.Errorf("LOCAL_PREBUILT_MODULE_FILE mismatch, actual: %s, expected: %s", actualPrebuiltModuleFile[0], expectedPrebuiltModuleFile) + } + + if len(actualSoongResourceExportPackage) != 1 { + t.Errorf("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE incorrect len %d", len(actualSoongResourceExportPackage)) + } else if actualSoongResourceExportPackage[0] != expectedSoongResourceExportPackage { + t.Errorf("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE mismatch, actual: %s, expected: %s", actualSoongResourceExportPackage[0], expectedSoongResourceExportPackage) + } +} + func TestAndroidTestImport(t *testing.T) { ctx, config := testJava(t, ` android_test_import { diff --git a/java/boot_image.go b/java/boot_image.go index 0a525b752..8a1e3c957 100644 --- a/java/boot_image.go +++ b/java/boot_image.go @@ -90,6 +90,10 @@ func (b *BootImageModule) DepIsInSameApex(ctx android.BaseModuleContext, dep and // The dex2oat tool is only needed for building and is not required in the apex. return false } + if android.IsMetaDependencyTag(tag) { + // Cross-cutting metadata dependencies are metadata. + return false + } panic(fmt.Errorf("boot_image module %q should not have a dependency on %q via tag %s", b, dep, android.PrettyPrintTag(tag))) } diff --git a/java/builder.go b/java/builder.go index 995160d0e..22a891ae1 100644 --- a/java/builder.go +++ b/java/builder.go @@ -193,12 +193,19 @@ var ( jarjar = pctx.AndroidStaticRule("jarjar", blueprint.RuleParams{ - Command: "${config.JavaCmd} ${config.JavaVmFlags}" + + Command: "" + + // Jarjar doesn't exit with an error when the rules file contains a syntax error, + // leading to stale or missing files later in the build. Remove the output file + // before running jarjar. + "rm -f ${out} && " + + "${config.JavaCmd} ${config.JavaVmFlags}" + // b/146418363 Enable Android specific jarjar transformer to drop compat annotations // for newly repackaged classes. Dropping @UnsupportedAppUsage on repackaged classes // avoids adding new hiddenapis after jarjar'ing. " -DremoveAndroidCompatAnnotations=true" + - " -jar ${config.JarjarCmd} process $rulesFile $in $out", + " -jar ${config.JarjarCmd} process $rulesFile $in $out && " + + // Turn a missing output file into a ninja error + `[ -e ${out} ] || (echo "Missing output file"; exit 1)`, CommandDeps: []string{"${config.JavaCmd}", "${config.JarjarCmd}", "$rulesFile"}, }, "rulesFile") diff --git a/java/config/Android.bp b/java/config/Android.bp index 198352187..194e2c6ed 100644 --- a/java/config/Android.bp +++ b/java/config/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-java-config", pkgPath: "android/soong/java/config", diff --git a/java/device_host_converter.go b/java/device_host_converter.go index 4914d74f6..ee7d01820 100644 --- a/java/device_host_converter.go +++ b/java/device_host_converter.go @@ -97,15 +97,15 @@ func (d *DeviceHostConverter) GenerateAndroidBuildActions(ctx android.ModuleCont } ctx.VisitDirectDepsWithTag(deviceHostConverterDepTag, func(m android.Module) { - if dep, ok := m.(Dependency); ok { - d.headerJars = append(d.headerJars, dep.HeaderJars()...) - d.implementationJars = append(d.implementationJars, dep.ImplementationJars()...) - d.implementationAndResourceJars = append(d.implementationAndResourceJars, dep.ImplementationAndResourcesJars()...) - d.resourceJars = append(d.resourceJars, dep.ResourceJars()...) - - srcJarArgs, srcJarDeps := dep.SrcJarArgs() - d.srcJarArgs = append(d.srcJarArgs, srcJarArgs...) - d.srcJarDeps = append(d.srcJarDeps, srcJarDeps...) + if ctx.OtherModuleHasProvider(m, JavaInfoProvider) { + dep := ctx.OtherModuleProvider(m, JavaInfoProvider).(JavaInfo) + d.headerJars = append(d.headerJars, dep.HeaderJars...) + d.implementationJars = append(d.implementationJars, dep.ImplementationJars...) + d.implementationAndResourceJars = append(d.implementationAndResourceJars, dep.ImplementationAndResourcesJars...) + d.resourceJars = append(d.resourceJars, dep.ResourceJars...) + + d.srcJarArgs = append(d.srcJarArgs, dep.SrcJarArgs...) + d.srcJarDeps = append(d.srcJarDeps, dep.SrcJarDeps...) } else { ctx.PropertyErrorf("libs", "module %q cannot be used as a dependency", ctx.OtherModuleName(m)) } @@ -131,9 +131,16 @@ func (d *DeviceHostConverter) GenerateAndroidBuildActions(ctx android.ModuleCont d.combinedHeaderJar = d.headerJars[0] } -} + ctx.SetProvider(JavaInfoProvider, JavaInfo{ + HeaderJars: d.headerJars, + ImplementationAndResourcesJars: d.implementationAndResourceJars, + ImplementationJars: d.implementationJars, + ResourceJars: d.resourceJars, + SrcJarArgs: d.srcJarArgs, + SrcJarDeps: d.srcJarDeps, + }) -var _ Dependency = (*DeviceHostConverter)(nil) +} func (d *DeviceHostConverter) HeaderJars() android.Paths { return d.headerJars diff --git a/java/dex.go b/java/dex.go index 24600c20f..e52fdb5d9 100644 --- a/java/dex.go +++ b/java/dex.go @@ -204,8 +204,9 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Fl // - prevent ProGuard stripping subclass in the support library that extends class added in the higher SDK version. // See b/20667396 var proguardRaiseDeps classpath - ctx.VisitDirectDepsWithTag(proguardRaiseTag, func(dep android.Module) { - proguardRaiseDeps = append(proguardRaiseDeps, dep.(Dependency).HeaderJars()...) + ctx.VisitDirectDepsWithTag(proguardRaiseTag, func(m android.Module) { + dep := ctx.OtherModuleProvider(m, JavaInfoProvider).(JavaInfo) + proguardRaiseDeps = append(proguardRaiseDeps, dep.HeaderJars...) }) r8Flags = append(r8Flags, proguardRaiseDeps.FormJavaClassPath("-libraryjars")) diff --git a/java/droiddoc.go b/java/droiddoc.go index c74009ea4..8f1644c7f 100644 --- a/java/droiddoc.go +++ b/java/droiddoc.go @@ -470,8 +470,9 @@ func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps { switch tag { case bootClasspathTag: - if dep, ok := module.(Dependency); ok { - deps.bootClasspath = append(deps.bootClasspath, dep.ImplementationJars()...) + if ctx.OtherModuleHasProvider(module, JavaInfoProvider) { + dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo) + deps.bootClasspath = append(deps.bootClasspath, dep.ImplementationJars...) } else if sm, ok := module.(SystemModulesProvider); ok { // A system modules dependency has been added to the bootclasspath // so add its libs to the bootclasspath. @@ -480,23 +481,23 @@ func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps { panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName())) } case libTag: - switch dep := module.(type) { - case SdkLibraryDependency: + if dep, ok := module.(SdkLibraryDependency); ok { deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...) - case Dependency: - deps.classpath = append(deps.classpath, dep.HeaderJars()...) - deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...) - case android.SourceFileProducer: + } else if ctx.OtherModuleHasProvider(module, JavaInfoProvider) { + dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo) + deps.classpath = append(deps.classpath, dep.HeaderJars...) + deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs...) + } else if dep, ok := module.(android.SourceFileProducer); ok { checkProducesJars(ctx, dep) deps.classpath = append(deps.classpath, dep.Srcs()...) - default: + } else { ctx.ModuleErrorf("depends on non-java module %q", otherName) } case java9LibTag: - switch dep := module.(type) { - case Dependency: - deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars()...) - default: + if ctx.OtherModuleHasProvider(module, JavaInfoProvider) { + dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo) + deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars...) + } else { ctx.ModuleErrorf("depends on non-java module %q", otherName) } case systemModulesTag: diff --git a/java/hiddenapi.go b/java/hiddenapi.go index eafbf5df0..1651c1c6d 100644 --- a/java/hiddenapi.go +++ b/java/hiddenapi.go @@ -28,10 +28,39 @@ var hiddenAPIGenerateCSVRule = pctx.AndroidStaticRule("hiddenAPIGenerateCSV", bl }, "outFlag", "stubAPIFlags") type hiddenAPI struct { + // The name of the module as it would be used in the boot jars configuration, e.g. without any + // prebuilt_ prefix (if it is a prebuilt), without any "-hiddenapi" suffix if it just provides + // annotations and without any ".impl" suffix if it is a java_sdk_library implementation library. + configurationName string + + // True if the module containing this structure contributes to the hiddenapi information or has + // that information encoded within it. + active bool + + // Identifies the active module variant which will be used as the source of hiddenapi information. + // + // A class may be compiled into a number of different module variants each of which will need the + // hiddenapi information encoded into it and so will be marked as active. However, only one of + // them must be used as a source of information by hiddenapi otherwise it will end up with + // duplicate entries. That module will have primary=true. + // + // Note, that modules <x>-hiddenapi that provide additional annotation information for module <x> + // that is on the bootclasspath are marked as primary=true as they are the primary source of that + // annotation information. + primary bool + + // True if the module only contains additional annotations and so does not require hiddenapi + // information to be encoded in its dex file and should not be used to generate the + // hiddenAPISingletonPathsStruct.stubFlags file. + annotationsOnly bool + // The path to the dex jar that is in the boot class path. If this is nil then the associated // module is not a boot jar, but could be one of the <x>-hiddenapi modules that provide additional // annotations for the <x> boot dex jar but which do not actually provide a boot dex jar // themselves. + // + // This must be the path to the unencoded dex jar as the encoded dex jar indirectly depends on + // this file so using the encoded dex jar here would result in a cycle in the ninja rules. bootDexJarPath android.Path // The path to the CSV file that contains mappings from Java signature to various flags derived @@ -89,52 +118,109 @@ type hiddenAPIIntf interface { var _ hiddenAPIIntf = (*hiddenAPI)(nil) -func (h *hiddenAPI) hiddenAPI(ctx android.ModuleContext, name string, primary bool, dexJar android.OutputPath, - implementationJar android.Path, uncompressDex bool) android.OutputPath { - if !ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { - - // Modules whose names are of the format <x>-hiddenapi provide hiddenapi information - // for the boot jar module <x>. Otherwise, the module provides information for itself. - // Either way extract the name of the boot jar module. - bootJarName := strings.TrimSuffix(name, "-hiddenapi") - - // If this module is on the boot jars list (or providing information for a module - // on the list) then extract the hiddenapi information from it, and if necessary - // encode that information in the generated dex file. - // - // It is important that hiddenapi information is only gathered for/from modules on - // that are actually on the boot jars list because the runtime only enforces access - // to the hidden API for the bootclassloader. If information is gathered for modules - // not on the list then that will cause failures in the CtsHiddenApiBlacklist... - // tests. - if inList(bootJarName, ctx.Config().BootJars()) { - // Create ninja rules to generate various CSV files needed by hiddenapi and store the paths - // in the hiddenAPI structure. - h.hiddenAPIGenerateCSV(ctx, implementationJar) - - // If this module is actually on the boot jars list and not providing - // hiddenapi information for a module on the boot jars list then encode - // the gathered information in the generated dex file. - if name == bootJarName { - hiddenAPIJar := android.PathForModuleOut(ctx, "hiddenapi", name+".jar").OutputPath - - // More than one library with the same classes can be encoded but only one can - // be added to the global set of flags, otherwise it will result in duplicate - // classes which is an error. Therefore, only add the dex jar of one of them - // to the global set of flags. - if primary { - h.bootDexJarPath = dexJar - } - hiddenAPIEncodeDex(ctx, hiddenAPIJar, dexJar, uncompressDex) - dexJar = hiddenAPIJar - } +// Initialize the hiddenapi structure +func (h *hiddenAPI) initHiddenAPI(ctx android.BaseModuleContext, name string) { + // If hiddenapi processing is disabled treat this as inactive. + if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { + return + } + + // Modules whose names are of the format <x>-hiddenapi provide hiddenapi information for the boot + // jar module <x>. Otherwise, the module provides information for itself. Either way extract the + // configurationName of the boot jar module. + configurationName := strings.TrimSuffix(name, "-hiddenapi") + h.configurationName = configurationName + + // It is important that hiddenapi information is only gathered for/from modules that are actually + // on the boot jars list because the runtime only enforces access to the hidden API for the + // bootclassloader. If information is gathered for modules not on the list then that will cause + // failures in the CtsHiddenApiBlocklist... tests. + h.active = inList(configurationName, ctx.Config().BootJars()) + if !h.active { + // The rest of the properties will be ignored if active is false. + return + } + + // If this module has a suffix of -hiddenapi then it only provides additional annotation + // information for a module on the boot jars list. + h.annotationsOnly = strings.HasSuffix(name, "-hiddenapi") + + // Determine whether this module is the primary module or not. + primary := true + + // A prebuilt module is only primary if it is preferred and conversely a source module is only + // primary if it has not been replaced by a prebuilt module. + module := ctx.Module() + if pi, ok := module.(android.PrebuiltInterface); ok { + if p := pi.Prebuilt(); p != nil { + primary = p.UsePrebuilt() } + } else { + // The only module that will pass a different name to its module name to this method is the + // implementation library of a java_sdk_library. It has a configuration name of <x> the same + // as its parent java_sdk_library but a module name of <x>.impl. It is not the primary module, + // the java_sdk_library with the name of <x> is. + primary = name == ctx.ModuleName() + + // A source module that has been replaced by a prebuilt can never be the primary module. + primary = primary && !module.IsReplacedByPrebuilt() + } + h.primary = primary +} + +// hiddenAPIExtractAndEncode is called by any module that could contribute to the hiddenapi +// processing. +// +// It ignores any module that has not had initHiddenApi() called on it and which is not in the boot +// jar list. +// +// Otherwise, it generates ninja rules to do the following: +// 1. Extract information needed for hiddenapi processing from the module and output it into CSV +// files. +// 2. Conditionally adds the supplied dex file to the list of files used to generate the +// hiddenAPISingletonPathsStruct.stubsFlag file. +// 3. Conditionally creates a copy of the supplied dex file into which it has encoded the hiddenapi +// flags and returns this instead of the supplied dex jar, otherwise simply returns the supplied +// dex jar. +func (h *hiddenAPI) hiddenAPIExtractAndEncode(ctx android.ModuleContext, dexJar android.OutputPath, + implementationJar android.Path, uncompressDex bool) android.OutputPath { + + if !h.active { + return dexJar + } + + h.hiddenAPIExtractInformation(ctx, dexJar, implementationJar) + + if !h.annotationsOnly { + hiddenAPIJar := android.PathForModuleOut(ctx, "hiddenapi", h.configurationName+".jar").OutputPath + + // Create a copy of the dex jar which has been encoded with hiddenapi flags. + hiddenAPIEncodeDex(ctx, hiddenAPIJar, dexJar, uncompressDex) + + // Use the encoded dex jar from here onwards. + dexJar = hiddenAPIJar } return dexJar } -func (h *hiddenAPI) hiddenAPIGenerateCSV(ctx android.ModuleContext, classesJar android.Path) { +// hiddenAPIExtractInformation generates ninja rules to extract the information from the classes +// jar, and outputs it to the appropriate module specific CSV file. +// +// It also makes the dex jar available for use when generating the +// hiddenAPISingletonPathsStruct.stubFlags. +func (h *hiddenAPI) hiddenAPIExtractInformation(ctx android.ModuleContext, dexJar, classesJar android.Path) { + if !h.active { + return + } + + // More than one library with the same classes may need to be encoded but only one should be + // used as a source of information for hidden API processing otherwise it will result in + // duplicate entries in the files. + if !h.primary { + return + } + stubFlagsCSV := hiddenAPISingletonPaths(ctx).stubFlags flagsCSV := android.PathForModuleOut(ctx, "hiddenapi", "flags.csv") @@ -173,6 +259,10 @@ func (h *hiddenAPI) hiddenAPIGenerateCSV(ctx android.ModuleContext, classesJar a FlagWithOutput("--output=", indexCSV) rule.Build("merged-hiddenapi-index", "Merged Hidden API index") h.indexCSVPath = indexCSV + + // Save the unencoded dex jar so it can be used when generating the + // hiddenAPISingletonPathsStruct.stubFlags file. + h.bootDexJarPath = dexJar } var hiddenAPIEncodeDexRule = pctx.AndroidStaticRule("hiddenAPIEncodeDex", blueprint.RuleParams{ diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go index 32d1e3faa..6341a3406 100644 --- a/java/hiddenapi_singleton.go +++ b/java/hiddenapi_singleton.go @@ -22,9 +22,13 @@ import ( ) func init() { - android.RegisterSingletonType("hiddenapi", hiddenAPISingletonFactory) - android.RegisterSingletonType("hiddenapi_index", hiddenAPIIndexSingletonFactory) - android.RegisterModuleType("hiddenapi_flags", hiddenAPIFlagsFactory) + RegisterHiddenApiSingletonComponents(android.InitRegistrationContext) +} + +func RegisterHiddenApiSingletonComponents(ctx android.RegistrationContext) { + ctx.RegisterSingletonType("hiddenapi", hiddenAPISingletonFactory) + ctx.RegisterSingletonType("hiddenapi_index", hiddenAPIIndexSingletonFactory) + ctx.RegisterModuleType("hiddenapi_flags", hiddenAPIFlagsFactory) } type hiddenAPISingletonPathsStruct struct { @@ -219,7 +223,7 @@ func stubFlagsRule(ctx android.SingletonContext) { ctx.VisitAllModules(func(module android.Module) { // Collect dex jar paths for the modules listed above. - if j, ok := module.(Dependency); ok { + if j, ok := module.(UsesLibraryDependency); ok { name := ctx.ModuleName(module) for moduleList, pathList := range moduleListToPathList { if i := android.IndexList(name, *moduleList); i != -1 { @@ -368,7 +372,7 @@ func flagsRule(ctx android.SingletonContext) android.Path { stubFlags := hiddenAPISingletonPaths(ctx).stubFlags rule.Command(). - Tool(android.PathForSource(ctx, "frameworks/base/tools/hiddenapi/generate_hiddenapi_lists.py")). + BuiltTool("generate_hiddenapi_lists"). FlagWithInput("--csv ", stubFlags). Inputs(flagsCSV). FlagWithInput("--unsupported ", diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go index 27f363e0c..df825bb3a 100644 --- a/java/hiddenapi_singleton_test.go +++ b/java/hiddenapi_singleton_test.go @@ -15,11 +15,12 @@ package java import ( - "android/soong/android" "fmt" "strings" "testing" + "android/soong/android" + "github.com/google/blueprint/proptools" ) @@ -32,7 +33,7 @@ func testConfigWithBootJars(bp string, bootJars []string, prebuiltHiddenApiDir * func testContextWithHiddenAPI(config android.Config) *android.TestContext { ctx := testContext(config) - ctx.RegisterSingletonType("hiddenapi", hiddenAPISingletonFactory) + RegisterHiddenApiSingletonComponents(ctx) return ctx } @@ -64,7 +65,7 @@ func TestHiddenAPISingleton(t *testing.T) { name: "foo", srcs: ["a.java"], compile_dex: true, - } + } `, []string{"platform:foo"}, nil) hiddenAPI := ctx.SingletonForTests("hiddenapi") @@ -75,6 +76,44 @@ func TestHiddenAPISingleton(t *testing.T) { } } +func TestHiddenAPIIndexSingleton(t *testing.T) { + ctx, _ := testHiddenAPIBootJars(t, ` + java_library { + name: "foo", + srcs: ["a.java"], + compile_dex: true, + } + + java_library { + name: "foo-hiddenapi", + srcs: ["a.java"], + compile_dex: true, + } + + java_import { + name: "foo", + jars: ["a.jar"], + compile_dex: true, + prefer: false, + } + + java_sdk_library { + name: "bar", + srcs: ["a.java"], + compile_dex: true, + } + `, []string{"platform:foo", "platform:bar"}, nil) + + hiddenAPIIndex := ctx.SingletonForTests("hiddenapi_index") + indexRule := hiddenAPIIndex.Rule("singleton-merged-hiddenapi-index") + CheckHiddenAPIRuleInputs(t, ` +.intermediates/bar/android_common/hiddenapi/index.csv +.intermediates/foo-hiddenapi/android_common/hiddenapi/index.csv +.intermediates/foo/android_common/hiddenapi/index.csv +`, + indexRule) +} + func TestHiddenAPISingletonWithPrebuilt(t *testing.T) { ctx, _ := testHiddenAPIBootJars(t, ` java_import { @@ -98,14 +137,14 @@ func TestHiddenAPISingletonWithPrebuiltUseSource(t *testing.T) { name: "foo", srcs: ["a.java"], compile_dex: true, - } + } java_import { name: "foo", jars: ["a.jar"], compile_dex: true, prefer: false, - } + } `, []string{"platform:foo"}, nil) hiddenAPI := ctx.SingletonForTests("hiddenapi") @@ -127,14 +166,14 @@ func TestHiddenAPISingletonWithPrebuiltOverrideSource(t *testing.T) { name: "foo", srcs: ["a.java"], compile_dex: true, - } + } java_import { name: "foo", jars: ["a.jar"], compile_dex: true, prefer: true, - } + } `, []string{"platform:foo"}, nil) hiddenAPI := ctx.SingletonForTests("hiddenapi") diff --git a/java/java.go b/java/java.go index bed232b4e..338140bbf 100644 --- a/java/java.go +++ b/java/java.go @@ -533,6 +533,53 @@ func (j *Module) OutputFiles(tag string) (android.Paths, error) { var _ android.OutputFileProducer = (*Module)(nil) +// JavaInfo contains information about a java module for use by modules that depend on it. +type JavaInfo struct { + // HeaderJars is a list of jars that can be passed as the javac classpath in order to link + // against this module. If empty, ImplementationJars should be used instead. + HeaderJars android.Paths + + // ImplementationAndResourceJars is a list of jars that contain the implementations of classes + // in the module as well as any resources included in the module. + ImplementationAndResourcesJars android.Paths + + // ImplementationJars is a list of jars that contain the implementations of classes in the + //module. + ImplementationJars android.Paths + + // ResourceJars is a list of jars that contain the resources included in the module. + ResourceJars android.Paths + + // AidlIncludeDirs is a list of directories that should be passed to the aidl tool when + // depending on this module. + AidlIncludeDirs android.Paths + + // SrcJarArgs is a list of arguments to pass to soong_zip to package the sources of this + // module. + SrcJarArgs []string + + // SrcJarDeps is a list of paths to depend on when packaging the sources of this module. + SrcJarDeps android.Paths + + // ExportedPlugins is a list of paths that should be used as annotation processors for any + // module that depends on this module. + ExportedPlugins android.Paths + + // ExportedPluginClasses is a list of classes that should be run as annotation processors for + // any module that depends on this module. + ExportedPluginClasses []string + + // ExportedPluginDisableTurbine is true if this module's annotation processors generate APIs, + // requiring disbling turbine for any modules that depend on it. + ExportedPluginDisableTurbine bool + + // JacocoReportClassesFile is the path to a jar containing uninstrumented classes that will be + // instrumented by jacoco. + JacocoReportClassesFile android.Path +} + +var JavaInfoProvider = blueprint.NewProvider(JavaInfo{}) + // Methods that need to be implemented for a module that is added to apex java_libs property. type ApexDependency interface { HeaderJars() android.Paths @@ -546,18 +593,6 @@ type UsesLibraryDependency interface { ClassLoaderContexts() dexpreopt.ClassLoaderContextMap } -type Dependency interface { - ApexDependency - UsesLibraryDependency - ImplementationJars() android.Paths - ResourceJars() android.Paths - AidlIncludeDirs() android.Paths - ExportedPlugins() (android.Paths, []string, bool) - SrcJarArgs() ([]string, android.Paths) - BaseModuleName() string - JacocoReportClassesFile() android.Path -} - type xref interface { XrefJavaFiles() android.Paths } @@ -1111,44 +1146,42 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { return } - switch dep := module.(type) { - case SdkLibraryDependency: + if dep, ok := module.(SdkLibraryDependency); ok { switch tag { case libTag: deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...) case staticLibTag: ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName) } - case Dependency: + } else if ctx.OtherModuleHasProvider(module, JavaInfoProvider) { + dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo) switch tag { case bootClasspathTag: - deps.bootClasspath = append(deps.bootClasspath, dep.HeaderJars()...) + deps.bootClasspath = append(deps.bootClasspath, dep.HeaderJars...) case libTag, instrumentationForTag: - deps.classpath = append(deps.classpath, dep.HeaderJars()...) - deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...) - pluginJars, pluginClasses, disableTurbine := dep.ExportedPlugins() - addPlugins(&deps, pluginJars, pluginClasses...) - deps.disableTurbine = deps.disableTurbine || disableTurbine + deps.classpath = append(deps.classpath, dep.HeaderJars...) + deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs...) + addPlugins(&deps, dep.ExportedPlugins, dep.ExportedPluginClasses...) + deps.disableTurbine = deps.disableTurbine || dep.ExportedPluginDisableTurbine case java9LibTag: - deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars()...) + deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars...) case staticLibTag: - deps.classpath = append(deps.classpath, dep.HeaderJars()...) - deps.staticJars = append(deps.staticJars, dep.ImplementationJars()...) - deps.staticHeaderJars = append(deps.staticHeaderJars, dep.HeaderJars()...) - deps.staticResourceJars = append(deps.staticResourceJars, dep.ResourceJars()...) - deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...) - pluginJars, pluginClasses, disableTurbine := dep.ExportedPlugins() - addPlugins(&deps, pluginJars, pluginClasses...) + deps.classpath = append(deps.classpath, dep.HeaderJars...) + deps.staticJars = append(deps.staticJars, dep.ImplementationJars...) + deps.staticHeaderJars = append(deps.staticHeaderJars, dep.HeaderJars...) + deps.staticResourceJars = append(deps.staticResourceJars, dep.ResourceJars...) + deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs...) + addPlugins(&deps, dep.ExportedPlugins, dep.ExportedPluginClasses...) // Turbine doesn't run annotation processors, so any module that uses an // annotation processor that generates API is incompatible with the turbine // optimization. - deps.disableTurbine = deps.disableTurbine || disableTurbine + deps.disableTurbine = deps.disableTurbine || dep.ExportedPluginDisableTurbine case pluginTag: - if plugin, ok := dep.(*Plugin); ok { + if plugin, ok := module.(*Plugin); ok { if plugin.pluginProperties.Processor_class != nil { - addPlugins(&deps, plugin.ImplementationAndResourcesJars(), *plugin.pluginProperties.Processor_class) + addPlugins(&deps, dep.ImplementationAndResourcesJars, *plugin.pluginProperties.Processor_class) } else { - addPlugins(&deps, plugin.ImplementationAndResourcesJars()) + addPlugins(&deps, dep.ImplementationAndResourcesJars) } // Turbine doesn't run annotation processors, so any module that uses an // annotation processor that generates API is incompatible with the turbine @@ -1158,14 +1191,14 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { ctx.PropertyErrorf("plugins", "%q is not a java_plugin module", otherName) } case errorpronePluginTag: - if plugin, ok := dep.(*Plugin); ok { - deps.errorProneProcessorPath = append(deps.errorProneProcessorPath, plugin.ImplementationAndResourcesJars()...) + if _, ok := module.(*Plugin); ok { + deps.errorProneProcessorPath = append(deps.errorProneProcessorPath, dep.ImplementationAndResourcesJars...) } else { ctx.PropertyErrorf("plugins", "%q is not a java_plugin module", otherName) } case exportedPluginTag: - if plugin, ok := dep.(*Plugin); ok { - j.exportedPluginJars = append(j.exportedPluginJars, plugin.ImplementationAndResourcesJars()...) + if plugin, ok := module.(*Plugin); ok { + j.exportedPluginJars = append(j.exportedPluginJars, dep.ImplementationAndResourcesJars...) if plugin.pluginProperties.Processor_class != nil { j.exportedPluginClasses = append(j.exportedPluginClasses, *plugin.pluginProperties.Processor_class) } @@ -1177,12 +1210,11 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { ctx.PropertyErrorf("exported_plugins", "%q is not a java_plugin module", otherName) } case kotlinStdlibTag: - deps.kotlinStdlib = append(deps.kotlinStdlib, dep.HeaderJars()...) + deps.kotlinStdlib = append(deps.kotlinStdlib, dep.HeaderJars...) case kotlinAnnotationsTag: - deps.kotlinAnnotations = dep.HeaderJars() + deps.kotlinAnnotations = dep.HeaderJars } - - case android.SourceFileProducer: + } else if dep, ok := module.(android.SourceFileProducer); ok { switch tag { case libTag: checkProducesJars(ctx, dep) @@ -1193,7 +1225,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { deps.staticJars = append(deps.staticJars, dep.Srcs()...) deps.staticHeaderJars = append(deps.staticHeaderJars, dep.Srcs()...) } - default: + } else { switch tag { case bootClasspathTag: // If a system modules dependency has been added to the bootclasspath @@ -1798,14 +1830,8 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { return } - configurationName := j.ConfigurationName() - primary := configurationName == ctx.ModuleName() - // If the prebuilt is being used rather than the from source, skip this - // module to prevent duplicated classes - primary = primary && !j.IsReplacedByPrebuilt() - // Hidden API CSV generation and dex encoding - dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, configurationName, primary, dexOutputFile, j.implementationJarFile, + dexOutputFile = j.hiddenAPIExtractAndEncode(ctx, dexOutputFile, j.implementationJarFile, proptools.Bool(j.dexProperties.Uncompress_dex)) // merge dex jar with resources if necessary @@ -1866,6 +1892,20 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { ctx.CheckbuildFile(outputFile) + ctx.SetProvider(JavaInfoProvider, JavaInfo{ + HeaderJars: android.PathsIfNonNil(j.headerJarFile), + ImplementationAndResourcesJars: android.PathsIfNonNil(j.implementationAndResourcesJar), + ImplementationJars: android.PathsIfNonNil(j.implementationJarFile), + ResourceJars: android.PathsIfNonNil(j.resourceJar), + AidlIncludeDirs: j.exportAidlIncludeDirs, + SrcJarArgs: j.srcJarArgs, + SrcJarDeps: j.srcJarDeps, + ExportedPlugins: j.exportedPluginJars, + ExportedPluginClasses: j.exportedPluginClasses, + ExportedPluginDisableTurbine: j.exportedDisableTurbine, + JacocoReportClassesFile: j.jacocoReportClassesFile, + }) + // Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource j.outputFile = outputFile.WithoutRel() } @@ -1973,8 +2013,6 @@ func (j *Module) instrument(ctx android.ModuleContext, flags javaBuilderFlags, return instrumentedJar } -var _ Dependency = (*Module)(nil) - func (j *Module) HeaderJars() android.Paths { if j.headerJarFile == nil { return nil @@ -2090,6 +2128,11 @@ func (j *Module) Stem() string { return proptools.StringDefault(j.deviceProperties.Stem, j.Name()) } +// ConfigurationName returns the name of the module as used in build configuration. +// +// This is usually the same as BaseModuleName() except for the <x>.impl libraries created by +// java_sdk_library in which case this is the BaseModuleName() without the ".impl" suffix, +// i.e. just <x>. func (j *Module) ConfigurationName() string { return proptools.StringDefault(j.deviceProperties.ConfigurationName, j.BaseModuleName()) } @@ -2149,6 +2192,11 @@ func shouldUncompressDex(ctx android.ModuleContext, dexpreopter *dexpreopter) bo } func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { + // Initialize the hiddenapi structure. Pass in the configuration name rather than the module name + // so the hidden api will encode the <x>.impl java_ library created by java_sdk_library just as it + // would the <x> library if <x> was configured as a boot jar. + j.initHiddenAPI(ctx, j.ConfigurationName()) + apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) if !apexInfo.IsForPlatform() { j.hideApexVariantFromMake = true @@ -2849,6 +2897,9 @@ func (j *Import) DepsMutator(ctx android.BottomUpMutatorContext) { } func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { + // Initialize the hiddenapi structure. + j.initHiddenAPI(ctx, j.BaseModuleName()) + if !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform() { j.hideApexVariantFromMake = true } @@ -2873,15 +2924,15 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.VisitDirectDeps(func(module android.Module) { tag := ctx.OtherModuleDependencyTag(module) - switch dep := module.(type) { - case Dependency: + if ctx.OtherModuleHasProvider(module, JavaInfoProvider) { + dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo) switch tag { case libTag, staticLibTag: - flags.classpath = append(flags.classpath, dep.HeaderJars()...) + flags.classpath = append(flags.classpath, dep.HeaderJars...) case bootClasspathTag: - flags.bootClasspath = append(flags.bootClasspath, dep.HeaderJars()...) + flags.bootClasspath = append(flags.bootClasspath, dep.HeaderJars...) } - case SdkLibraryDependency: + } else if dep, ok := module.(SdkLibraryDependency); ok { switch tag { case libTag: flags.classpath = append(flags.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...) @@ -2917,8 +2968,10 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { // Get the path of the dex implementation jar from the `deapexer` module. di := ctx.OtherModuleProvider(deapexerModule, android.DeapexerProvider).(android.DeapexerInfo) - j.dexJarFile = di.PrebuiltExportPath(j.BaseModuleName(), ".dexjar") - if j.dexJarFile == nil { + if dexOutputPath := di.PrebuiltExportPath(j.BaseModuleName(), ".dexjar"); dexOutputPath != nil { + j.dexJarFile = dexOutputPath + j.hiddenAPIExtractInformation(ctx, dexOutputPath, outputFile) + } else { // This should never happen as a variant for a prebuilt_apex is only created if the // prebuilt_apex has been configured to export the java library dex file. ctx.ModuleErrorf("internal error: no dex implementation jar available from prebuilt_apex %q", deapexerModule.Name()) @@ -2948,16 +3001,20 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { return } - configurationName := j.BaseModuleName() - primary := j.Prebuilt().UsePrebuilt() - // Hidden API CSV generation and dex encoding - dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, configurationName, primary, dexOutputFile, outputFile, + dexOutputFile = j.hiddenAPIExtractAndEncode(ctx, dexOutputFile, outputFile, proptools.Bool(j.dexProperties.Uncompress_dex)) j.dexJarFile = dexOutputFile } } + + ctx.SetProvider(JavaInfoProvider, JavaInfo{ + HeaderJars: android.PathsIfNonNil(j.combinedClasspathFile), + ImplementationAndResourcesJars: android.PathsIfNonNil(j.combinedClasspathFile), + ImplementationJars: android.PathsIfNonNil(j.combinedClasspathFile), + AidlIncludeDirs: j.exportAidlIncludeDirs, + }) } func (j *Import) OutputFiles(tag string) (android.Paths, error) { @@ -2971,8 +3028,6 @@ func (j *Import) OutputFiles(tag string) (android.Paths, error) { var _ android.OutputFileProducer = (*Import)(nil) -var _ Dependency = (*Import)(nil) - func (j *Import) HeaderJars() android.Paths { if j.combinedClasspathFile == nil { return nil @@ -3318,6 +3373,7 @@ func DefaultsFactory() android.Module { &android.ApexProperties{}, &RuntimeResourceOverlayProperties{}, &LintProperties{}, + &appTestHelperAppProperties{}, ) android.InitDefaultsModule(module) diff --git a/java/jdeps.go b/java/jdeps.go index 2b5ee7491..0ab2e422b 100644 --- a/java/jdeps.go +++ b/java/jdeps.go @@ -87,8 +87,9 @@ func (j *jdepsGeneratorSingleton) GenerateBuildActions(ctx android.SingletonCont dpInfo.Classes = append(dpInfo.Classes, data.Class) } - if dep, ok := module.(Dependency); ok { - dpInfo.Installed_paths = append(dpInfo.Installed_paths, dep.ImplementationJars().Strings()...) + if ctx.ModuleHasProvider(module, JavaInfoProvider) { + dep := ctx.ModuleProvider(module, JavaInfoProvider).(JavaInfo) + dpInfo.Installed_paths = append(dpInfo.Installed_paths, dep.ImplementationJars.Strings()...) } dpInfo.Classes = android.FirstUniqueStrings(dpInfo.Classes) dpInfo.Installed_paths = android.FirstUniqueStrings(dpInfo.Installed_paths) diff --git a/java/lint.go b/java/lint.go index cd2a904d6..c9e0cdd2f 100644 --- a/java/lint.go +++ b/java/lint.go @@ -276,8 +276,9 @@ func (l *linter) lint(ctx android.ModuleContext) { extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag) for _, extraLintCheckModule := range extraLintCheckModules { - if dep, ok := extraLintCheckModule.(Dependency); ok { - l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars()...) + if ctx.OtherModuleHasProvider(extraLintCheckModule, JavaInfoProvider) { + dep := ctx.OtherModuleProvider(extraLintCheckModule, JavaInfoProvider).(JavaInfo) + l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars...) } else { ctx.PropertyErrorf("lint.extra_check_modules", "%s is not a java module", ctx.OtherModuleName(extraLintCheckModule)) diff --git a/java/robolectric.go b/java/robolectric.go index c821e5bd3..98bb71040 100644 --- a/java/robolectric.go +++ b/java/robolectric.go @@ -148,10 +148,10 @@ func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) } for _, dep := range ctx.GetDirectDepsWithTag(libTag) { - m := dep.(Dependency) - r.libs = append(r.libs, m.BaseModuleName()) - if !android.InList(m.BaseModuleName(), config.FrameworkLibraries) { - combinedJarJars = append(combinedJarJars, m.ImplementationAndResourcesJars()...) + m := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo) + r.libs = append(r.libs, ctx.OtherModuleName(dep)) + if !android.InList(ctx.OtherModuleName(dep), config.FrameworkLibraries) { + combinedJarJars = append(combinedJarJars, m.ImplementationAndResourcesJars...) } } @@ -245,10 +245,10 @@ func (r *robolectricTest) generateRoboSrcJar(ctx android.ModuleContext, outputFi srcJarDeps := append(android.Paths(nil), instrumentedApp.srcJarDeps...) for _, m := range ctx.GetDirectDepsWithTag(roboCoverageLibsTag) { - if dep, ok := m.(Dependency); ok { - depSrcJarArgs, depSrcJarDeps := dep.SrcJarArgs() - srcJarArgs = append(srcJarArgs, depSrcJarArgs...) - srcJarDeps = append(srcJarDeps, depSrcJarDeps...) + if ctx.OtherModuleHasProvider(m, JavaInfoProvider) { + dep := ctx.OtherModuleProvider(m, JavaInfoProvider).(JavaInfo) + srcJarArgs = append(srcJarArgs, dep.SrcJarArgs...) + srcJarDeps = append(srcJarDeps, dep.SrcJarDeps...) } } diff --git a/java/sdk.go b/java/sdk.go index e82bd9c7b..74d5a81a9 100644 --- a/java/sdk.go +++ b/java/sdk.go @@ -566,10 +566,11 @@ func createFrameworkAidl(stubsModules []string, path android.OutputPath, ctx and ctx.VisitAllModules(func(module android.Module) { // Collect dex jar paths for the modules listed above. - if j, ok := module.(Dependency); ok { + if ctx.ModuleHasProvider(module, JavaInfoProvider) { + j := ctx.ModuleProvider(module, JavaInfoProvider).(JavaInfo) name := ctx.ModuleName(module) if i := android.IndexList(name, stubsModules); i != -1 { - stubsJars[i] = j.HeaderJars() + stubsJars[i] = j.HeaderJars } } }) diff --git a/java/sdk_library.go b/java/sdk_library.go index 638740f4f..aa96e0dac 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -60,12 +60,12 @@ type scopeDependencyTag struct { apiScope *apiScope // Function for extracting appropriate path information from the dependency. - depInfoExtractor func(paths *scopePaths, dep android.Module) error + depInfoExtractor func(paths *scopePaths, ctx android.ModuleContext, dep android.Module) error } // Extract tag specific information from the dependency. func (tag scopeDependencyTag) extractDepInfo(ctx android.ModuleContext, dep android.Module, paths *scopePaths) { - err := tag.depInfoExtractor(paths, dep) + err := tag.depInfoExtractor(paths, ctx, dep) if err != nil { ctx.ModuleErrorf("has an invalid {scopeDependencyTag: %s} dependency on module %s: %s", tag.name, ctx.OtherModuleName(dep), err.Error()) } @@ -539,13 +539,14 @@ type scopePaths struct { stubsSrcJar android.OptionalPath } -func (paths *scopePaths) extractStubsLibraryInfoFromDependency(dep android.Module) error { - if lib, ok := dep.(Dependency); ok { - paths.stubsHeaderPath = lib.HeaderJars() - paths.stubsImplPath = lib.ImplementationJars() +func (paths *scopePaths) extractStubsLibraryInfoFromDependency(ctx android.ModuleContext, dep android.Module) error { + if ctx.OtherModuleHasProvider(dep, JavaInfoProvider) { + lib := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo) + paths.stubsHeaderPath = lib.HeaderJars + paths.stubsImplPath = lib.ImplementationJars return nil } else { - return fmt.Errorf("expected module that implements Dependency, e.g. java_library") + return fmt.Errorf("expected module that has JavaInfoProvider, e.g. java_library") } } @@ -572,7 +573,7 @@ func (paths *scopePaths) extractApiInfoFromApiStubsProvider(provider ApiStubsPro paths.removedApiFilePath = android.OptionalPathForPath(provider.RemovedApiFilePath()) } -func (paths *scopePaths) extractApiInfoFromDep(dep android.Module) error { +func (paths *scopePaths) extractApiInfoFromDep(ctx android.ModuleContext, dep android.Module) error { return paths.treatDepAsApiStubsProvider(dep, func(provider ApiStubsProvider) { paths.extractApiInfoFromApiStubsProvider(provider) }) @@ -582,13 +583,13 @@ func (paths *scopePaths) extractStubsSourceInfoFromApiStubsProviders(provider Ap paths.stubsSrcJar = android.OptionalPathForPath(provider.StubsSrcJar()) } -func (paths *scopePaths) extractStubsSourceInfoFromDep(dep android.Module) error { +func (paths *scopePaths) extractStubsSourceInfoFromDep(ctx android.ModuleContext, dep android.Module) error { return paths.treatDepAsApiStubsSrcProvider(dep, func(provider ApiStubsSrcProvider) { paths.extractStubsSourceInfoFromApiStubsProviders(provider) }) } -func (paths *scopePaths) extractStubsSourceAndApiInfoFromApiStubsProvider(dep android.Module) error { +func (paths *scopePaths) extractStubsSourceAndApiInfoFromApiStubsProvider(ctx android.ModuleContext, dep android.Module) error { return paths.treatDepAsApiStubsProvider(dep, func(provider ApiStubsProvider) { paths.extractApiInfoFromApiStubsProvider(provider) paths.extractStubsSourceInfoFromApiStubsProviders(provider) @@ -951,7 +952,6 @@ type SdkLibrary struct { commonToSdkLibraryAndImport } -var _ Dependency = (*SdkLibrary)(nil) var _ SdkLibraryDependency = (*SdkLibrary)(nil) func (module *SdkLibrary) generateTestAndSystemScopesByDefault() bool { diff --git a/java/system_modules.go b/java/system_modules.go index 5cc546d2e..95f71b80f 100644 --- a/java/system_modules.go +++ b/java/system_modules.go @@ -160,8 +160,8 @@ func (system *SystemModules) GenerateAndroidBuildActions(ctx android.ModuleConte var jars android.Paths ctx.VisitDirectDepsWithTag(systemModulesLibsTag, func(module android.Module) { - dep, _ := module.(Dependency) - jars = append(jars, dep.HeaderJars()...) + dep, _ := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo) + jars = append(jars, dep.HeaderJars...) }) system.headerJars = jars diff --git a/java/testing.go b/java/testing.go index 5fcf84c6b..781106ff2 100644 --- a/java/testing.go +++ b/java/testing.go @@ -18,6 +18,7 @@ import ( "fmt" "reflect" "sort" + "strings" "testing" "android/soong/android" @@ -237,3 +238,11 @@ func CheckModuleDependencies(t *testing.T, ctx *android.TestContext, name, varia t.Errorf("expected %#q, found %#q", expected, actual) } } + +func CheckHiddenAPIRuleInputs(t *testing.T, expected string, hiddenAPIRule android.TestingBuildParams) { + actual := strings.TrimSpace(strings.Join(android.NormalizePathsForTesting(hiddenAPIRule.Implicits), "\n")) + expected = strings.TrimSpace(expected) + if actual != expected { + t.Errorf("Expected hiddenapi rule inputs:\n%s\nactual inputs:\n%s", expected, actual) + } +} diff --git a/kernel/Android.bp b/kernel/Android.bp index f8a48d956..91e749070 100644 --- a/kernel/Android.bp +++ b/kernel/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-kernel", pkgPath: "android/soong/kernel", diff --git a/licenses/Android.bp b/licenses/Android.bp index f4a76d7e1..c70d6bd55 100644 --- a/licenses/Android.bp +++ b/licenses/Android.bp @@ -307,10 +307,7 @@ license_kind { license_kind { name: "SPDX-license-identifier-Beerware", - conditions: [ - "by_exception_only", - "not_allowed", - ], + conditions: ["notice"], url: "https://spdx.org/licenses/Beerware.html", } @@ -1137,10 +1134,7 @@ license_kind { license_kind { name: "SPDX-license-identifier-WTFPL", - conditions: [ - "by_exception_only", - "not_allowed", - ], + conditions: ["notice"], url: "https://spdx.org/licenses/WTFPL.html", } diff --git a/linkerconfig/Android.bp b/linkerconfig/Android.bp index 8807a2e68..9161f0eb5 100644 --- a/linkerconfig/Android.bp +++ b/linkerconfig/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-linkerconfig", pkgPath: "android/soong/linkerconfig", diff --git a/linkerconfig/proto/Android.bp b/linkerconfig/proto/Android.bp index 4d971288d..3b1e4ab9b 100644 --- a/linkerconfig/proto/Android.bp +++ b/linkerconfig/proto/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + cc_library_static { name: "lib_linker_config_proto_lite", host_supported: true, diff --git a/makedeps/Android.bp b/makedeps/Android.bp index b77b08f0d..62bdfd503 100644 --- a/makedeps/Android.bp +++ b/makedeps/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-makedeps", pkgPath: "android/soong/makedeps", diff --git a/partner/Android.bp b/partner/Android.bp index f2ced8dd3..7fc873eec 100644 --- a/partner/Android.bp +++ b/partner/Android.bp @@ -16,6 +16,10 @@ // Sample project for creating an extended androidmk // +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + blueprint_go_binary { name: "partner_androidmk", srcs: [ diff --git a/phony/Android.bp b/phony/Android.bp index 2c423ef75..db5efc98e 100644 --- a/phony/Android.bp +++ b/phony/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-phony", pkgPath: "android/soong/phony", diff --git a/python/Android.bp b/python/Android.bp index ffd03fe89..b633f1e3f 100644 --- a/python/Android.bp +++ b/python/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-python", pkgPath: "android/soong/python", diff --git a/python/tests/Android.bp b/python/tests/Android.bp index c8bf42023..0e8eef6ef 100644 --- a/python/tests/Android.bp +++ b/python/tests/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + python_test_host { name: "par_test", main: "par_test.py", diff --git a/remoteexec/Android.bp b/remoteexec/Android.bp index fc2c0e324..9f75df5a3 100644 --- a/remoteexec/Android.bp +++ b/remoteexec/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-remoteexec", pkgPath: "android/soong/remoteexec", diff --git a/rust/Android.bp b/rust/Android.bp index ad3040afd..8b2aa30d0 100644 --- a/rust/Android.bp +++ b/rust/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-rust", pkgPath: "android/soong/rust", diff --git a/rust/compiler.go b/rust/compiler.go index 586063e91..c26f208ee 100644 --- a/rust/compiler.go +++ b/rust/compiler.go @@ -232,6 +232,10 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags) Flag flags.LinkFlags = append(flags.LinkFlags, "-Wl,-rpath,"+rpathPrefix+"../"+rpath) } + if ctx.RustModule().UseVndk() { + flags.RustFlags = append(flags.RustFlags, "--cfg 'android_vndk'") + } + return flags } @@ -254,7 +258,7 @@ func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps { if !Bool(compiler.Properties.No_stdlibs) { for _, stdlib := range config.Stdlibs { // If we're building for the primary arch of the build host, use the compiler's stdlibs - if ctx.Target().Os == android.BuildOs && ctx.TargetPrimary() { + if ctx.Target().Os == android.BuildOs { stdlib = stdlib + "_" + ctx.toolchain().RustTriple() } diff --git a/rust/config/Android.bp b/rust/config/Android.bp index 1f0109f0d..5b121c3aa 100644 --- a/rust/config/Android.bp +++ b/rust/config/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-rust-config", pkgPath: "android/soong/rust/config", diff --git a/rust/image.go b/rust/image.go index ac8c1b32c..628aca3e4 100644 --- a/rust/image.go +++ b/rust/image.go @@ -24,7 +24,7 @@ import ( var _ android.ImageInterface = (*Module)(nil) func (mod *Module) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { - return false + return mod.Properties.VendorRamdiskVariantNeeded } func (mod *Module) CoreVariantNeeded(ctx android.BaseModuleContext) bool { @@ -52,6 +52,10 @@ func (mod *Module) InRecovery() bool { return false } +func (mod *Module) InVendorRamdisk() bool { + return mod.ModuleBase.InVendorRamdisk() || mod.ModuleBase.InstallInVendorRamdisk() +} + func (mod *Module) OnlyInRamdisk() bool { // TODO(b/165791368) return false @@ -86,7 +90,9 @@ func (c *Module) InProduct() bool { func (mod *Module) SetImageVariation(ctx android.BaseModuleContext, variant string, module android.Module) { m := module.(*Module) - if strings.HasPrefix(variant, cc.VendorVariationPrefix) { + if variant == android.VendorRamdiskVariation { + m.MakeAsPlatform() + } else if strings.HasPrefix(variant, cc.VendorVariationPrefix) { m.Properties.ImageVariationPrefix = cc.VendorVariationPrefix m.Properties.VndkVersion = strings.TrimPrefix(variant, cc.VendorVariationPrefix) @@ -117,6 +123,8 @@ func (mod *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { } coreVariantNeeded := true + vendorRamdiskVariantNeeded := false + var vendorVariants []string if mod.HasVendorVariant() { @@ -138,15 +146,23 @@ func (mod *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { // We can't check shared() here because image mutator is called before the library mutator, so we need to // check buildShared() if lib.buildShared() { - mctx.PropertyErrorf(prop, "can only be set for rust_ffi_static modules.") + mctx.PropertyErrorf(prop, "cannot be set for rust_ffi or rust_ffi_shared modules.") } else { vendorVariants = append(vendorVariants, platformVndkVersion) } } } + if Bool(mod.Properties.Vendor_ramdisk_available) { + if lib, ok := mod.compiler.(libraryInterface); !ok || (ok && lib.buildShared()) { + mctx.PropertyErrorf("vendor_ramdisk_available", "cannot be set for rust_ffi or rust_ffi_shared modules.") + } else { + vendorRamdiskVariantNeeded = true + } + } + if vendorSpecific { - if lib, ok := mod.compiler.(libraryInterface); !ok || (ok && !lib.static()) { + if lib, ok := mod.compiler.(libraryInterface); !ok || (ok && (lib.buildShared() || lib.buildDylib() || lib.buildRlib())) { mctx.ModuleErrorf("Rust vendor specific modules are currently only supported for rust_ffi_static modules.") } else { coreVariantNeeded = false @@ -155,6 +171,8 @@ func (mod *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { } mod.Properties.CoreVariantNeeded = coreVariantNeeded + mod.Properties.VendorRamdiskVariantNeeded = vendorRamdiskVariantNeeded + for _, variant := range android.FirstUniqueStrings(vendorVariants) { mod.Properties.ExtraVariants = append(mod.Properties.ExtraVariants, cc.VendorVariationPrefix+variant) } diff --git a/rust/image_test.go b/rust/image_test.go index fd719628b..e40599c3a 100644 --- a/rust/image_test.go +++ b/rust/image_test.go @@ -15,15 +15,16 @@ package rust import ( + "strings" "testing" "android/soong/android" "android/soong/cc" ) -// Test that cc_binaries can link against rust_ffi_static libraries. +// Test that cc modules can link against vendor_available rust_ffi_static libraries. func TestVendorLinkage(t *testing.T) { - ctx := testRust(t, ` + ctx := testRustVndk(t, ` cc_binary { name: "fizz_vendor", static_libs: ["libfoo_vendor"], @@ -37,16 +38,58 @@ func TestVendorLinkage(t *testing.T) { } `) - vendorBinary := ctx.ModuleForTests("fizz_vendor", "android_arm64_armv8-a").Module().(*cc.Module) + vendorBinary := ctx.ModuleForTests("fizz_vendor", "android_vendor.VER_arm64_armv8-a").Module().(*cc.Module) if !android.InList("libfoo_vendor", vendorBinary.Properties.AndroidMkStaticLibs) { t.Errorf("vendorBinary should have a dependency on libfoo_vendor") } } +// Test that variants which use the vndk emit the appropriate cfg flag. +func TestImageVndkCfgFlag(t *testing.T) { + ctx := testRustVndk(t, ` + rust_ffi_static { + name: "libfoo", + crate_name: "foo", + srcs: ["foo.rs"], + vendor_available: true, + } + `) + + vendor := ctx.ModuleForTests("libfoo", "android_vendor.VER_arm64_armv8-a_static").Rule("rustc") + + if !strings.Contains(vendor.Args["rustcFlags"], "--cfg 'android_vndk'") { + t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo vendor variant, rustcFlags: %#v", vendor.Args["rustcFlags"]) + } +} + +// Test that cc modules can link against vendor_ramdisk_available rust_ffi_static libraries. +func TestVendorRamdiskLinkage(t *testing.T) { + ctx := testRustVndk(t, ` + cc_library_static { + name: "libcc_vendor_ramdisk", + static_libs: ["libfoo_vendor_ramdisk"], + system_shared_libs: [], + vendor_ramdisk_available: true, + } + rust_ffi_static { + name: "libfoo_vendor_ramdisk", + crate_name: "foo", + srcs: ["foo.rs"], + vendor_ramdisk_available: true, + } + `) + + vendorRamdiskLibrary := ctx.ModuleForTests("libcc_vendor_ramdisk", "android_vendor_ramdisk_arm64_armv8-a_static").Module().(*cc.Module) + + if !android.InList("libfoo_vendor_ramdisk.vendor_ramdisk", vendorRamdiskLibrary.Properties.AndroidMkStaticLibs) { + t.Errorf("libcc_vendor_ramdisk should have a dependency on libfoo_vendor_ramdisk") + } +} + // Test that shared libraries cannot be made vendor available until proper support is added. func TestForbiddenVendorLinkage(t *testing.T) { - testRustError(t, "can only be set for rust_ffi_static modules", ` + testRustError(t, "cannot be set for rust_ffi or rust_ffi_shared modules.", ` rust_ffi_shared { name: "libfoo_vendor", crate_name: "foo", @@ -54,6 +97,14 @@ func TestForbiddenVendorLinkage(t *testing.T) { vendor_available: true, } `) + testRustError(t, "cannot be set for rust_ffi or rust_ffi_shared modules.", ` + rust_ffi_shared { + name: "libfoo_vendor", + crate_name: "foo", + srcs: ["foo.rs"], + vendor_ramdisk_available: true, + } + `) testRustError(t, "Rust vendor specific modules are currently only supported for rust_ffi_static modules.", ` rust_ffi { name: "libfoo_vendor", @@ -70,4 +121,13 @@ func TestForbiddenVendorLinkage(t *testing.T) { vendor: true, } `) + testRustError(t, "Rust vendor specific modules are currently only supported for rust_ffi_static modules.", ` + rust_binary { + name: "foo_vendor", + crate_name: "foo", + srcs: ["foo.rs"], + vendor: true, + } + `) + } diff --git a/rust/rust.go b/rust/rust.go index 0b733cc35..dc23abb8d 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -74,8 +74,16 @@ type BaseProperties struct { SubName string `blueprint:"mutated"` // Set by imageMutator - CoreVariantNeeded bool `blueprint:"mutated"` - ExtraVariants []string `blueprint:"mutated"` + CoreVariantNeeded bool `blueprint:"mutated"` + VendorRamdiskVariantNeeded bool `blueprint:"mutated"` + ExtraVariants []string `blueprint:"mutated"` + + // Make this module available when building for vendor ramdisk. + // On device without a dedicated recovery partition, the module is only + // available after switching root into + // /first_stage_ramdisk. To expose the module before switching root, install + // the recovery variant instead (TODO(b/165791368) recovery not yet supported) + Vendor_ramdisk_available *bool // Minimum sdk version that the artifact should support when it runs as part of mainline modules(APEX). Min_sdk_version *string @@ -658,7 +666,9 @@ func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { // Differentiate static libraries that are vendor available if mod.UseVndk() { - mod.Properties.SubName += ".vendor" + mod.Properties.SubName += cc.VendorSuffix + } else if mod.InVendorRamdisk() && !mod.OnlyInVendorRamdisk() { + mod.Properties.SubName += cc.VendorRamdiskSuffix } if !toolchain.Supported() { diff --git a/rust/rust_test.go b/rust/rust_test.go index 88d964300..a0ed5345f 100644 --- a/rust/rust_test.go +++ b/rust/rust_test.go @@ -64,6 +64,14 @@ func testRust(t *testing.T, bp string) *android.TestContext { return tctx.parse(t) } +func testRustVndk(t *testing.T, bp string) *android.TestContext { + tctx := newTestRustCtx(t, bp) + tctx.useMockedFs() + tctx.generateConfig() + tctx.setVndk(t) + return tctx.parse(t) +} + // testRustCov returns a TestContext in which a basic environment has been // setup. This environment explicitly enables coverage. func testRustCov(t *testing.T, bp string) *android.TestContext { @@ -140,6 +148,15 @@ func (tctx *testRustCtx) enableCoverage(t *testing.T) { tctx.config.TestProductVariables.NativeCoveragePaths = []string{"*"} } +func (tctx *testRustCtx) setVndk(t *testing.T) { + if tctx.config == nil { + t.Fatalf("tctx.config not been generated yet. Please call generateConfig first.") + } + tctx.config.TestProductVariables.DeviceVndkVersion = StringPtr("current") + tctx.config.TestProductVariables.ProductVndkVersion = StringPtr("current") + tctx.config.TestProductVariables.Platform_vndk_version = StringPtr("VER") +} + // parse validates the configuration and parses the Blueprint file. It returns // a TestContext which can be used to retrieve the generated modules via // ModuleForTests. diff --git a/rust/test.go b/rust/test.go index 3fa5f954a..6caa7b168 100644 --- a/rust/test.go +++ b/rust/test.go @@ -15,6 +15,8 @@ package rust import ( + "github.com/google/blueprint/proptools" + "android/soong/android" "android/soong/tradefed" ) @@ -127,6 +129,9 @@ func (test *testDecorator) install(ctx ModuleContext) { ctx.PropertyErrorf("no_named_install_directory", "Module install directory may only be disabled if relative_install_path is set") } + if ctx.Host() && test.Properties.Test_options.Unit_test == nil { + test.Properties.Test_options.Unit_test = proptools.BoolPtr(true) + } test.binaryDecorator.install(ctx) } diff --git a/rust/testing.go b/rust/testing.go index bb511b648..1afe27ef0 100644 --- a/rust/testing.go +++ b/rust/testing.go @@ -46,6 +46,30 @@ func GatherRequiredDepsForTest() string { sysroot: true, } rust_prebuilt_library { + name: "libstd_i686-unknown-linux-gnu", + crate_name: "std", + rlib: { + srcs: ["libstd.rlib"], + }, + dylib: { + srcs: ["libstd.so"], + }, + host_supported: true, + sysroot: true, + } + rust_prebuilt_library { + name: "libtest_i686-unknown-linux-gnu", + crate_name: "test", + rlib: { + srcs: ["libtest.rlib"], + }, + dylib: { + srcs: ["libtest.so"], + }, + host_supported: true, + sysroot: true, + } + rust_prebuilt_library { name: "libstd_x86_64-apple-darwin", crate_name: "std", rlib: { @@ -101,6 +125,7 @@ func GatherRequiredDepsForTest() string { no_stdlibs: true, host_supported: true, vendor_available: true, + vendor_ramdisk_available: true, native_coverage: false, sysroot: true, apex_available: ["//apex_available:platform", "//apex_available:anyapex"], @@ -113,6 +138,7 @@ func GatherRequiredDepsForTest() string { no_stdlibs: true, host_supported: true, vendor_available: true, + vendor_ramdisk_available: true, native_coverage: false, sysroot: true, apex_available: ["//apex_available:platform", "//apex_available:anyapex"], diff --git a/scripts/Android.bp b/scripts/Android.bp index dd03f283a..b9163ccf1 100644 --- a/scripts/Android.bp +++ b/scripts/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + python_binary_host { name: "check_boot_jars", main: "check_boot_jars/check_boot_jars.py", diff --git a/scripts/build-mainline-modules.sh b/scripts/build-mainline-modules.sh index b8485ea3d..ac67438fa 100755 --- a/scripts/build-mainline-modules.sh +++ b/scripts/build-mainline-modules.sh @@ -26,6 +26,8 @@ MODULES_SDK_AND_EXPORTS=( platform-mainline-test-exports runtime-module-host-exports runtime-module-sdk + stats-log-api-gen-exports + statsd-module-sdk tzdata-module-test-exports ) diff --git a/scripts/gen_ndk_backedby_apex.sh b/scripts/gen_ndk_backedby_apex.sh index e0da60236..4abaaba41 100755 --- a/scripts/gen_ndk_backedby_apex.sh +++ b/scripts/gen_ndk_backedby_apex.sh @@ -23,33 +23,50 @@ printHelp() { echo "**************************** Usage Instructions ****************************" echo "This script is used to generate the Mainline modules backed-by NDK symbols." echo "" - echo "To run this script use: ./ndk_backedby_module.sh \$BINARY_IMAGE_DIRECTORY \$OUTPUT_FILE_PATH \$NDK_LIB_NAME_LIST" - echo "For example: If all the module image files that you would like to run is under directory '/myModule' and output write to /backedby.txt then the command would be:" - echo "./ndk_usedby_module.sh /myModule /backedby.txt /ndkLibList.txt" + echo "To run this script use: ./gen_ndk_backed_by_apex.sh \$OUTPUT_FILE_PATH \$NDK_LIB_NAME_LIST \$MODULE_LIB1 \$MODULE_LIB2..." + echo "For example: If output write to /backedby.txt then the command would be:" + echo "./gen_ndk_backed_by_apex.sh /backedby.txt /ndkLibList.txt lib1.so lib2.so" echo "If the module1 is backing lib1 then the backedby.txt would contains: " echo "lib1" } +contains() { + val="$1" + shift + for x in "$@"; do + if [ "$x" = "$val" ]; then + return 0 + fi + done + return 1 +} + + genBackedByList() { - dir="$1" - [[ ! -e "$2" ]] && echo "" >> "$2" + out="$1" + shift + ndk_list="$1" + shift + rm -f "$out" + touch "$out" while IFS= read -r line do soFileName=$(echo "$line" | sed 's/\(.*so\).*/\1/') if [[ ! -z "$soFileName" && "$soFileName" != *"#"* ]] then - find "$dir" -type f -name "$soFileName" -exec echo "$soFileName" >> "$2" \; + if contains "$soFileName" "$@"; then + echo "$soFileName" >> "$out" + fi fi - done < "$3" + done < "$ndk_list" } if [[ "$1" == "help" ]] then printHelp -elif [[ "$#" -ne 3 ]] +elif [[ "$#" -lt 2 ]] then - echo "Wrong argument length. Expecting 3 argument representing image file directory, output path, path to ndk library list." + echo "Wrong argument length. Expecting at least 2 argument representing output path, path to ndk library list, followed by a list of libraries in the Mainline module." else - [[ -e "$2" ]] && rm "$2" - genBackedByList "$1" "$2" "$3" + genBackedByList "$@" fi diff --git a/scripts/hiddenapi/Android.bp b/scripts/hiddenapi/Android.bp new file mode 100644 index 000000000..a669cadd4 --- /dev/null +++ b/scripts/hiddenapi/Android.bp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +python_binary_host { + name: "merge_csv", + main: "merge_csv.py", + srcs: ["merge_csv.py"], + version: { + py2: { + enabled: false, + }, + py3: { + enabled: true, + embedded_launcher: true, + }, + }, +} + +python_binary_host { + name: "generate_hiddenapi_lists", + main: "generate_hiddenapi_lists.py", + srcs: ["generate_hiddenapi_lists.py"], + version: { + py2: { + enabled: false, + }, + py3: { + enabled: true, + embedded_launcher: true, + }, + }, +} diff --git a/scripts/hiddenapi/generate_hiddenapi_lists.py b/scripts/hiddenapi/generate_hiddenapi_lists.py new file mode 100755 index 000000000..681647548 --- /dev/null +++ b/scripts/hiddenapi/generate_hiddenapi_lists.py @@ -0,0 +1,383 @@ +#!/usr/bin/env python +# +# 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. +"""Generate API lists for non-SDK API enforcement.""" +import argparse +from collections import defaultdict, namedtuple +import functools +import os +import re +import sys + +# Names of flags recognized by the `hiddenapi` tool. +FLAG_SDK = 'sdk' +FLAG_UNSUPPORTED = 'unsupported' +FLAG_BLOCKED = 'blocked' +FLAG_MAX_TARGET_O = 'max-target-o' +FLAG_MAX_TARGET_P = 'max-target-p' +FLAG_MAX_TARGET_Q = 'max-target-q' +FLAG_MAX_TARGET_R = 'max-target-r' +FLAG_CORE_PLATFORM_API = 'core-platform-api' +FLAG_PUBLIC_API = 'public-api' +FLAG_SYSTEM_API = 'system-api' +FLAG_TEST_API = 'test-api' + +# List of all known flags. +FLAGS_API_LIST = [ + FLAG_SDK, + FLAG_UNSUPPORTED, + FLAG_BLOCKED, + FLAG_MAX_TARGET_O, + FLAG_MAX_TARGET_P, + FLAG_MAX_TARGET_Q, + FLAG_MAX_TARGET_R, +] +ALL_FLAGS = FLAGS_API_LIST + [ + FLAG_CORE_PLATFORM_API, + FLAG_PUBLIC_API, + FLAG_SYSTEM_API, + FLAG_TEST_API, +] + +FLAGS_API_LIST_SET = set(FLAGS_API_LIST) +ALL_FLAGS_SET = set(ALL_FLAGS) + +# Option specified after one of FLAGS_API_LIST to indicate that +# only known and otherwise unassigned entries should be assign the +# given flag. +# For example, the max-target-P list is checked in as it was in P, +# but signatures have changes since then. The flag instructs this +# script to skip any entries which do not exist any more. +FLAG_IGNORE_CONFLICTS = "ignore-conflicts" + +# Option specified after one of FLAGS_API_LIST to express that all +# apis within a given set of packages should be assign the given flag. +FLAG_PACKAGES = "packages" + +# Option specified after one of FLAGS_API_LIST to indicate an extra +# tag that should be added to the matching APIs. +FLAG_TAG = "tag" + +# Regex patterns of fields/methods used in serialization. These are +# considered public API despite being hidden. +SERIALIZATION_PATTERNS = [ + r'readObject\(Ljava/io/ObjectInputStream;\)V', + r'readObjectNoData\(\)V', + r'readResolve\(\)Ljava/lang/Object;', + r'serialVersionUID:J', + r'serialPersistentFields:\[Ljava/io/ObjectStreamField;', + r'writeObject\(Ljava/io/ObjectOutputStream;\)V', + r'writeReplace\(\)Ljava/lang/Object;', +] + +# Single regex used to match serialization API. It combines all the +# SERIALIZATION_PATTERNS into a single regular expression. +SERIALIZATION_REGEX = re.compile(r'.*->(' + '|'.join(SERIALIZATION_PATTERNS) + r')$') + +# Predicates to be used with filter_apis. +HAS_NO_API_LIST_ASSIGNED = lambda api, flags: not FLAGS_API_LIST_SET.intersection(flags) +IS_SERIALIZATION = lambda api, flags: SERIALIZATION_REGEX.match(api) + + +class StoreOrderedOptions(argparse.Action): + """An argparse action that stores a number of option arguments in the order that + they were specified. + """ + def __call__(self, parser, args, values, option_string = None): + items = getattr(args, self.dest, None) + if items is None: + items = [] + items.append([option_string.lstrip('-'), values]) + setattr(args, self.dest, items) + +def get_args(): + """Parses command line arguments. + + Returns: + Namespace: dictionary of parsed arguments + """ + parser = argparse.ArgumentParser() + parser.add_argument('--output', required=True) + parser.add_argument('--csv', nargs='*', default=[], metavar='CSV_FILE', + help='CSV files to be merged into output') + + for flag in ALL_FLAGS: + parser.add_argument('--' + flag, dest='ordered_flags', metavar='TXT_FILE', + action=StoreOrderedOptions, help='lists of entries with flag "' + flag + '"') + parser.add_argument('--' + FLAG_IGNORE_CONFLICTS, dest='ordered_flags', nargs=0, + action=StoreOrderedOptions, help='Indicates that only known and otherwise unassigned ' + 'entries should be assign the given flag. Must follow a list of entries and applies ' + 'to the preceding such list.') + parser.add_argument('--' + FLAG_PACKAGES, dest='ordered_flags', nargs=0, + action=StoreOrderedOptions, help='Indicates that the previous list of entries ' + 'is a list of packages. All members in those packages will be given the flag. ' + 'Must follow a list of entries and applies to the preceding such list.') + parser.add_argument('--' + FLAG_TAG, dest='ordered_flags', nargs=1, + action=StoreOrderedOptions, help='Adds an extra tag to the previous list of entries. ' + 'Must follow a list of entries and applies to the preceding such list.') + + return parser.parse_args() + + +def read_lines(filename): + """Reads entire file and return it as a list of lines. + + Lines which begin with a hash are ignored. + + Args: + filename (string): Path to the file to read from. + + Returns: + Lines of the file as a list of string. + """ + with open(filename, 'r') as f: + lines = f.readlines(); + lines = filter(lambda line: not line.startswith('#'), lines) + lines = map(lambda line: line.strip(), lines) + return set(lines) + + +def write_lines(filename, lines): + """Writes list of lines into a file, overwriting the file if it exists. + + Args: + filename (string): Path to the file to be writing into. + lines (list): List of strings to write into the file. + """ + lines = map(lambda line: line + '\n', lines) + with open(filename, 'w') as f: + f.writelines(lines) + + +def extract_package(signature): + """Extracts the package from a signature. + + Args: + signature (string): JNI signature of a method or field. + + Returns: + The package name of the class containing the field/method. + """ + full_class_name = signature.split(";->")[0] + # Example: Landroid/hardware/radio/V1_2/IRadio$Proxy + if (full_class_name[0] != "L"): + raise ValueError("Expected to start with 'L': %s" % full_class_name) + full_class_name = full_class_name[1:] + # If full_class_name doesn't contain '/', then package_name will be ''. + package_name = full_class_name.rpartition("/")[0] + return package_name.replace('/', '.') + + +class FlagsDict: + def __init__(self): + self._dict_keyset = set() + self._dict = defaultdict(set) + + def _check_entries_set(self, keys_subset, source): + assert isinstance(keys_subset, set) + assert keys_subset.issubset(self._dict_keyset), ( + "Error: {} specifies signatures not present in code:\n" + "{}" + "Please visit go/hiddenapi for more information.").format( + source, "".join(map(lambda x: " " + str(x) + "\n", keys_subset - self._dict_keyset))) + + def _check_flags_set(self, flags_subset, source): + assert isinstance(flags_subset, set) + assert flags_subset.issubset(ALL_FLAGS_SET), ( + "Error processing: {}\n" + "The following flags were not recognized: \n" + "{}\n" + "Please visit go/hiddenapi for more information.").format( + source, "\n".join(flags_subset - ALL_FLAGS_SET)) + + def filter_apis(self, filter_fn): + """Returns APIs which match a given predicate. + + This is a helper function which allows to filter on both signatures (keys) and + flags (values). The built-in filter() invokes the lambda only with dict's keys. + + Args: + filter_fn : Function which takes two arguments (signature/flags) and returns a boolean. + + Returns: + A set of APIs which match the predicate. + """ + return set(filter(lambda x: filter_fn(x, self._dict[x]), self._dict_keyset)) + + def get_valid_subset_of_unassigned_apis(self, api_subset): + """Sanitizes a key set input to only include keys which exist in the dictionary + and have not been assigned any API list flags. + + Args: + entries_subset (set/list): Key set to be sanitized. + + Returns: + Sanitized key set. + """ + assert isinstance(api_subset, set) + return api_subset.intersection(self.filter_apis(HAS_NO_API_LIST_ASSIGNED)) + + def generate_csv(self): + """Constructs CSV entries from a dictionary. + + Old versions of flags are used to generate the file. + + Returns: + List of lines comprising a CSV file. See "parse_and_merge_csv" for format description. + """ + lines = [] + for api in self._dict: + flags = sorted(self._dict[api]) + lines.append(",".join([api] + flags)) + return sorted(lines) + + def parse_and_merge_csv(self, csv_lines, source = "<unknown>"): + """Parses CSV entries and merges them into a given dictionary. + + The expected CSV format is: + <api signature>,<flag1>,<flag2>,...,<flagN> + + Args: + csv_lines (list of strings): Lines read from a CSV file. + source (string): Origin of `csv_lines`. Will be printed in error messages. + + Throws: + AssertionError if parsed flags are invalid. + """ + # Split CSV lines into arrays of values. + csv_values = [ line.split(',') for line in csv_lines ] + + # Update the full set of API signatures. + self._dict_keyset.update([ csv[0] for csv in csv_values ]) + + # Check that all flags are known. + csv_flags = set() + for csv in csv_values: + csv_flags.update(csv[1:]) + self._check_flags_set(csv_flags, source) + + # Iterate over all CSV lines, find entry in dict and append flags to it. + for csv in csv_values: + flags = csv[1:] + if (FLAG_PUBLIC_API in flags) or (FLAG_SYSTEM_API in flags): + flags.append(FLAG_SDK) + self._dict[csv[0]].update(flags) + + def assign_flag(self, flag, apis, source="<unknown>", tag = None): + """Assigns a flag to given subset of entries. + + Args: + flag (string): One of ALL_FLAGS. + apis (set): Subset of APIs to receive the flag. + source (string): Origin of `entries_subset`. Will be printed in error messages. + + Throws: + AssertionError if parsed API signatures of flags are invalid. + """ + # Check that all APIs exist in the dict. + self._check_entries_set(apis, source) + + # Check that the flag is known. + self._check_flags_set(set([ flag ]), source) + + # Iterate over the API subset, find each entry in dict and assign the flag to it. + for api in apis: + self._dict[api].add(flag) + if tag: + self._dict[api].add(tag) + + +FlagFile = namedtuple('FlagFile', ('flag', 'file', 'ignore_conflicts', 'packages', 'tag')) + +def parse_ordered_flags(ordered_flags): + r = [] + currentflag, file, ignore_conflicts, packages, tag = None, None, False, False, None + for flag_value in ordered_flags: + flag, value = flag_value[0], flag_value[1] + if flag in ALL_FLAGS_SET: + if currentflag: + r.append(FlagFile(currentflag, file, ignore_conflicts, packages, tag)) + ignore_conflicts, packages, tag = False, False, None + currentflag = flag + file = value + else: + if currentflag is None: + raise argparse.ArgumentError('--%s is only allowed after one of %s' % ( + flag, ' '.join(['--%s' % f for f in ALL_FLAGS_SET]))) + if flag == FLAG_IGNORE_CONFLICTS: + ignore_conflicts = True + elif flag == FLAG_PACKAGES: + packages = True + elif flag == FLAG_TAG: + tag = value[0] + + + if currentflag: + r.append(FlagFile(currentflag, file, ignore_conflicts, packages, tag)) + return r + + +def main(argv): + # Parse arguments. + args = vars(get_args()) + flagfiles = parse_ordered_flags(args['ordered_flags']) + + # Initialize API->flags dictionary. + flags = FlagsDict() + + # Merge input CSV files into the dictionary. + # Do this first because CSV files produced by parsing API stubs will + # contain the full set of APIs. Subsequent additions from text files + # will be able to detect invalid entries, and/or filter all as-yet + # unassigned entries. + for filename in args["csv"]: + flags.parse_and_merge_csv(read_lines(filename), filename) + + # Combine inputs which do not require any particular order. + # (1) Assign serialization API to SDK. + flags.assign_flag(FLAG_SDK, flags.filter_apis(IS_SERIALIZATION)) + + # (2) Merge text files with a known flag into the dictionary. + for info in flagfiles: + if (not info.ignore_conflicts) and (not info.packages): + flags.assign_flag(info.flag, read_lines(info.file), info.file, info.tag) + + # Merge text files where conflicts should be ignored. + # This will only assign the given flag if: + # (a) the entry exists, and + # (b) it has not been assigned any other flag. + # Because of (b), this must run after all strict assignments have been performed. + for info in flagfiles: + if info.ignore_conflicts: + valid_entries = flags.get_valid_subset_of_unassigned_apis(read_lines(info.file)) + flags.assign_flag(info.flag, valid_entries, filename, info.tag) + + # All members in the specified packages will be assigned the appropriate flag. + for info in flagfiles: + if info.packages: + packages_needing_list = set(read_lines(info.file)) + should_add_signature_to_list = lambda sig,lists: extract_package( + sig) in packages_needing_list and not lists + valid_entries = flags.filter_apis(should_add_signature_to_list) + flags.assign_flag(info.flag, valid_entries, info.file, info.tag) + + # Mark all remaining entries as blocked. + flags.assign_flag(FLAG_BLOCKED, flags.filter_apis(HAS_NO_API_LIST_ASSIGNED)) + + # Write output. + write_lines(args["output"], flags.generate_csv()) + +if __name__ == "__main__": + main(sys.argv) diff --git a/scripts/hiddenapi/generate_hiddenapi_lists_test.py b/scripts/hiddenapi/generate_hiddenapi_lists_test.py new file mode 100755 index 000000000..ff3d70881 --- /dev/null +++ b/scripts/hiddenapi/generate_hiddenapi_lists_test.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python +# +# 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. +"""Unit tests for Hidden API list generation.""" +import unittest +from generate_hiddenapi_lists import * + +class TestHiddenapiListGeneration(unittest.TestCase): + + def test_filter_apis(self): + # Initialize flags so that A and B are put on the allow list and + # C, D, E are left unassigned. Try filtering for the unassigned ones. + flags = FlagsDict() + flags.parse_and_merge_csv(['A,' + FLAG_SDK, 'B,' + FLAG_SDK, + 'C', 'D', 'E']) + filter_set = flags.filter_apis(lambda api, flags: not flags) + self.assertTrue(isinstance(filter_set, set)) + self.assertEqual(filter_set, set([ 'C', 'D', 'E' ])) + + def test_get_valid_subset_of_unassigned_keys(self): + # Create flags where only A is unassigned. + flags = FlagsDict() + flags.parse_and_merge_csv(['A,' + FLAG_SDK, 'B', 'C']) + flags.assign_flag(FLAG_UNSUPPORTED, set(['C'])) + self.assertEqual(flags.generate_csv(), + [ 'A,' + FLAG_SDK, 'B', 'C,' + FLAG_UNSUPPORTED ]) + + # Check three things: + # (1) B is selected as valid unassigned + # (2) A is not selected because it is assigned to the allow list + # (3) D is not selected because it is not a valid key + self.assertEqual( + flags.get_valid_subset_of_unassigned_apis(set(['A', 'B', 'D'])), set([ 'B' ])) + + def test_parse_and_merge_csv(self): + flags = FlagsDict() + + # Test empty CSV entry. + self.assertEqual(flags.generate_csv(), []) + + # Test new additions. + flags.parse_and_merge_csv([ + 'A,' + FLAG_UNSUPPORTED, + 'B,' + FLAG_BLOCKED + ',' + FLAG_MAX_TARGET_O, + 'C,' + FLAG_SDK + ',' + FLAG_SYSTEM_API, + 'D,' + FLAG_UNSUPPORTED + ',' + FLAG_TEST_API, + 'E,' + FLAG_BLOCKED + ',' + FLAG_TEST_API, + ]) + self.assertEqual(flags.generate_csv(), [ + 'A,' + FLAG_UNSUPPORTED, + 'B,' + FLAG_BLOCKED + "," + FLAG_MAX_TARGET_O, + 'C,' + FLAG_SDK + ',' + FLAG_SYSTEM_API, + 'D,' + FLAG_TEST_API + ',' + FLAG_UNSUPPORTED, + 'E,' + FLAG_BLOCKED + ',' + FLAG_TEST_API, + ]) + + # Test unknown flag. + with self.assertRaises(AssertionError): + flags.parse_and_merge_csv([ 'Z,foo' ]) + + def test_assign_flag(self): + flags = FlagsDict() + flags.parse_and_merge_csv(['A,' + FLAG_SDK, 'B']) + + # Test new additions. + flags.assign_flag(FLAG_UNSUPPORTED, set([ 'A', 'B' ])) + self.assertEqual(flags.generate_csv(), + [ 'A,' + FLAG_SDK + "," + FLAG_UNSUPPORTED, 'B,' + FLAG_UNSUPPORTED ]) + + # Test invalid API signature. + with self.assertRaises(AssertionError): + flags.assign_flag(FLAG_SDK, set([ 'C' ])) + + # Test invalid flag. + with self.assertRaises(AssertionError): + flags.assign_flag('foo', set([ 'A' ])) + + def test_extract_package(self): + signature = 'Lcom/foo/bar/Baz;->method1()Lcom/bar/Baz;' + expected_package = 'com.foo.bar' + self.assertEqual(extract_package(signature), expected_package) + + signature = 'Lcom/foo1/bar/MyClass;->method2()V' + expected_package = 'com.foo1.bar' + self.assertEqual(extract_package(signature), expected_package) + + signature = 'Lcom/foo_bar/baz/MyClass;->method3()V' + expected_package = 'com.foo_bar.baz' + self.assertEqual(extract_package(signature), expected_package) + +if __name__ == '__main__': + unittest.main() diff --git a/scripts/hiddenapi/merge_csv.py b/scripts/hiddenapi/merge_csv.py new file mode 100755 index 000000000..6a5b0e134 --- /dev/null +++ b/scripts/hiddenapi/merge_csv.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python +# +# 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. +""" +Merge multiple CSV files, possibly with different columns. +""" + +import argparse +import csv +import io + +from zipfile import ZipFile + +args_parser = argparse.ArgumentParser(description='Merge given CSV files into a single one.') +args_parser.add_argument('--header', help='Comma separated field names; ' + 'if missing determines the header from input files.') +args_parser.add_argument('--zip_input', help='ZIP archive with all CSV files to merge.') +args_parser.add_argument('--output', help='Output file for merged CSV.', + default='-', type=argparse.FileType('w')) +args_parser.add_argument('files', nargs=argparse.REMAINDER) +args = args_parser.parse_args() + + +def dict_reader(input): + return csv.DictReader(input, delimiter=',', quotechar='|') + + +if args.zip_input and len(args.files) > 0: + raise ValueError('Expecting either a single ZIP with CSV files' + ' or a list of CSV files as input; not both.') + +csv_readers = [] +if len(args.files) > 0: + for file in args.files: + csv_readers.append(dict_reader(open(file, 'r'))) +elif args.zip_input: + with ZipFile(args.zip_input) as zip: + for entry in zip.namelist(): + if entry.endswith('.uau'): + csv_readers.append(dict_reader(io.TextIOWrapper(zip.open(entry, 'r')))) + +headers = set() +if args.header: + fieldnames = args.header.split(',') +else: + # Build union of all columns from source files: + for reader in csv_readers: + headers = headers.union(reader.fieldnames) + fieldnames = sorted(headers) + +# Concatenate all files to output: +writer = csv.DictWriter(args.output, delimiter=',', quotechar='|', quoting=csv.QUOTE_MINIMAL, + dialect='unix', fieldnames=fieldnames) +writer.writeheader() +for reader in csv_readers: + for row in reader: + writer.writerow(row) diff --git a/sdk/Android.bp b/sdk/Android.bp index cb93351d9..8a3119c5e 100644 --- a/sdk/Android.bp +++ b/sdk/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-sdk", pkgPath: "android/soong/sdk", diff --git a/sh/Android.bp b/sh/Android.bp index e5ffeefb4..f9198dc4f 100644 --- a/sh/Android.bp +++ b/sh/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-sh", pkgPath: "android/soong/sh", diff --git a/sh/sh_binary.go b/sh/sh_binary.go index 66e493bf1..54dfc2467 100644 --- a/sh/sh_binary.go +++ b/sh/sh_binary.go @@ -24,6 +24,7 @@ import ( "github.com/google/blueprint/proptools" "android/soong/android" + "android/soong/bazel" "android/soong/cc" "android/soong/tradefed" ) @@ -43,6 +44,8 @@ func init() { android.RegisterModuleType("sh_binary_host", ShBinaryHostFactory) android.RegisterModuleType("sh_test", ShTestFactory) android.RegisterModuleType("sh_test_host", ShTestHostFactory) + + android.RegisterBp2BuildMutator("sh_binary", ShBinaryBp2Build) } type shBinaryProperties struct { @@ -81,6 +84,9 @@ type shBinaryProperties struct { // Make this module available when building for recovery. Recovery_available *bool + + // Properties for Bazel migration purposes. + bazel.Properties } type TestProperties struct { @@ -461,4 +467,62 @@ func ShTestHostFactory() android.Module { return module } +type bazelShBinaryAttributes struct { + Srcs bazel.LabelList + // Bazel also supports the attributes below, but (so far) these are not required for Bionic + // deps + // data + // args + // compatible_with + // deprecation + // distribs + // env + // exec_compatible_with + // exec_properties + // features + // licenses + // output_licenses + // restricted_to + // tags + // target_compatible_with + // testonly + // toolchains + // visibility +} + +type bazelShBinary struct { + android.BazelTargetModuleBase + bazelShBinaryAttributes +} + +func BazelShBinaryFactory() android.Module { + module := &bazelShBinary{} + module.AddProperties(&module.bazelShBinaryAttributes) + android.InitBazelTargetModule(module) + return module +} + +func ShBinaryBp2Build(ctx android.TopDownMutatorContext) { + m, ok := ctx.Module().(*ShBinary) + if !ok || !m.properties.Bazel_module.Bp2build_available { + return + } + + srcs := android.BazelLabelForModuleSrc(ctx, []string{*m.properties.Src}) + + attrs := &bazelShBinaryAttributes{ + Srcs: srcs, + } + + props := bazel.NewBazelTargetModuleProperties(m.Name(), "sh_binary", "") + + ctx.CreateBazelTargetModule(BazelShBinaryFactory, props, attrs) +} + +func (m *bazelShBinary) Name() string { + return m.BaseModuleName() +} + +func (m *bazelShBinary) GenerateAndroidBuildActions(ctx android.ModuleContext) {} + var Bool = proptools.Bool diff --git a/shared/Android.bp b/shared/Android.bp index 2a4f56f77..5aa9d54f7 100644 --- a/shared/Android.bp +++ b/shared/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-shared", pkgPath: "android/soong/shared", diff --git a/symbol_inject/Android.bp b/symbol_inject/Android.bp index 8308043cd..718024817 100644 --- a/symbol_inject/Android.bp +++ b/symbol_inject/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-symbol_inject", pkgPath: "android/soong/symbol_inject", diff --git a/symbol_inject/cmd/Android.bp b/symbol_inject/cmd/Android.bp index ee2f25932..ac23f00ea 100644 --- a/symbol_inject/cmd/Android.bp +++ b/symbol_inject/cmd/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + blueprint_go_binary { name: "symbol_inject", deps: ["soong-symbol_inject"], diff --git a/sysprop/Android.bp b/sysprop/Android.bp index 48094f1ef..540a8dae8 100644 --- a/sysprop/Android.bp +++ b/sysprop/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-sysprop", pkgPath: "android/soong/sysprop", diff --git a/third_party/zip/Android.bp b/third_party/zip/Android.bp index ec89c0c0d..f279d12cd 100644 --- a/third_party/zip/Android.bp +++ b/third_party/zip/Android.bp @@ -12,6 +12,21 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: [ + "Android-Apache-2.0", + "build_soong_third_party_zip_license", + ], +} + +license { + name: "build_soong_third_party_zip_license", + license_kinds: [ + "SPDX-license-identifier-BSD", + ], + license_text: ["LICENSE"], +} + bootstrap_go_package { name: "android-archive-zip", pkgPath: "android/soong/third_party/zip", diff --git a/third_party/zip/LICENSE b/third_party/zip/LICENSE new file mode 100644 index 000000000..e5c5bafb3 --- /dev/null +++ b/third_party/zip/LICENSE @@ -0,0 +1,28 @@ +Copyright 2009, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of the Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tradefed/Android.bp b/tradefed/Android.bp index 4e4e6a7ee..f0336a34f 100644 --- a/tradefed/Android.bp +++ b/tradefed/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-tradefed", pkgPath: "android/soong/tradefed", diff --git a/ui/build/Android.bp b/ui/build/Android.bp index c314b7b08..32b6edade 100644 --- a/ui/build/Android.bp +++ b/ui/build/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-ui-build-paths", pkgPath: "android/soong/ui/build/paths", diff --git a/ui/logger/Android.bp b/ui/logger/Android.bp index 8091ef927..269a5a084 100644 --- a/ui/logger/Android.bp +++ b/ui/logger/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-ui-logger", pkgPath: "android/soong/ui/logger", diff --git a/ui/metrics/Android.bp b/ui/metrics/Android.bp index 95c8f5c24..c428ec482 100644 --- a/ui/metrics/Android.bp +++ b/ui/metrics/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-ui-metrics", pkgPath: "android/soong/ui/metrics", diff --git a/ui/metrics/proc/Android.bp b/ui/metrics/proc/Android.bp index 32d821750..4501fedd2 100644 --- a/ui/metrics/proc/Android.bp +++ b/ui/metrics/proc/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-ui-metrics-proc", pkgPath: "android/soong/ui/metrics/proc", diff --git a/ui/status/Android.bp b/ui/status/Android.bp index 19e5a2ad3..ac31390eb 100644 --- a/ui/status/Android.bp +++ b/ui/status/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-ui-status", pkgPath: "android/soong/ui/status", diff --git a/ui/terminal/Android.bp b/ui/terminal/Android.bp index aa6e35d2b..fdf300faa 100644 --- a/ui/terminal/Android.bp +++ b/ui/terminal/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-ui-terminal", pkgPath: "android/soong/ui/terminal", diff --git a/ui/tracer/Android.bp b/ui/tracer/Android.bp index af588f1d5..d8942fd70 100644 --- a/ui/tracer/Android.bp +++ b/ui/tracer/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-ui-tracer", pkgPath: "android/soong/ui/tracer", diff --git a/xml/Android.bp b/xml/Android.bp index cd25cff7b..a5e5f4c7f 100644 --- a/xml/Android.bp +++ b/xml/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-xml", pkgPath: "android/soong/xml", diff --git a/zip/Android.bp b/zip/Android.bp index 5081e91c8..b28adbd51 100644 --- a/zip/Android.bp +++ b/zip/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + subdirs = ["cmd"] bootstrap_go_package { diff --git a/zip/cmd/Android.bp b/zip/cmd/Android.bp index 6029a694f..43bf232a0 100644 --- a/zip/cmd/Android.bp +++ b/zip/cmd/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + blueprint_go_binary { name: "soong_zip", deps: [ |