Merge "rust: Allow rust_ffi_shared in jni_libs" into tm-mainline-prod
diff --git a/android/Android.bp b/android/Android.bp
index d583703..65332b2 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -49,6 +49,7 @@
"expand.go",
"filegroup.go",
"fixture.go",
+ "gen_notice.go",
"hooks.go",
"image.go",
"license.go",
@@ -106,6 +107,7 @@
"deptag_test.go",
"expand_test.go",
"fixture_test.go",
+ "gen_notice_test.go",
"license_kind_test.go",
"license_test.go",
"licenses_test.go",
diff --git a/android/androidmk.go b/android/androidmk.go
index 5c715b4..1a9cabd 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -288,6 +288,8 @@
// The contributions to the dist.
type distContributions struct {
+ // Path to license metadata file.
+ licenseMetadataFile Path
// List of goals and the dist copy instructions.
copiesForGoals []*copiesForGoals
}
@@ -364,6 +366,8 @@
// Collate the contributions this module makes to the dist.
distContributions := &distContributions{}
+ distContributions.licenseMetadataFile = amod.licenseMetadataFile
+
// Iterate over this module's dist structs, merged from the dist and dists properties.
for _, dist := range amod.Dists() {
// Get the list of goals this dist should be enabled for. e.g. sdk, droidcore
@@ -456,6 +460,10 @@
for _, c := range d.copies {
ret = append(
ret,
+ fmt.Sprintf("$(if $(strip $(ALL_TARGETS.%s.META_LIC)),,$(eval ALL_TARGETS.%s.META_LIC := %s))\n",
+ c.from.String(), c.from.String(), distContributions.licenseMetadataFile.String()))
+ ret = append(
+ ret,
fmt.Sprintf("$(call dist-for-goals,%s,%s:%s)\n", d.goals, c.from.String(), c.dest))
}
}
@@ -597,7 +605,7 @@
}
if len(base.noticeFiles) > 0 {
- a.SetString("LOCAL_NOTICE_FILE", strings.Join(base.noticeFiles.Strings(), " "))
+ a.AddStrings("LOCAL_NOTICE_FILE", strings.Join(base.noticeFiles.Strings(), " "))
}
if host {
diff --git a/android/androidmk_test.go b/android/androidmk_test.go
index caf11f1..ae2187f 100644
--- a/android/androidmk_test.go
+++ b/android/androidmk_test.go
@@ -50,6 +50,8 @@
func (m *customModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+ m.base().licenseMetadataFile = PathForOutput(ctx, "meta_lic")
+
// If the dist_output_file: true then create an output file that is stored in
// the OutputFile property of the AndroidMkEntry.
if proptools.BoolDefault(m.properties.Dist_output_file, true) {
@@ -198,10 +200,13 @@
},
}
+ dc.licenseMetadataFile = PathForTesting("meta_lic")
makeOutput := generateDistContributionsForMake(dc)
assertStringEquals(t, `.PHONY: my_goal
+$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))
$(call dist-for-goals,my_goal,one.out:one.out)
+$(if $(strip $(ALL_TARGETS.two.out.META_LIC)),,$(eval ALL_TARGETS.two.out.META_LIC := meta_lic))
$(call dist-for-goals,my_goal,two.out:other.out)
`, strings.Join(makeOutput, ""))
}
@@ -243,18 +248,26 @@
expectedAndroidMkLines := []string{
".PHONY: my_second_goal\n",
+ "$(if $(strip $(ALL_TARGETS.two.out.META_LIC)),,$(eval ALL_TARGETS.two.out.META_LIC := meta_lic))\n",
"$(call dist-for-goals,my_second_goal,two.out:two.out)\n",
+ "$(if $(strip $(ALL_TARGETS.three/four.out.META_LIC)),,$(eval ALL_TARGETS.three/four.out.META_LIC := meta_lic))\n",
"$(call dist-for-goals,my_second_goal,three/four.out:four.out)\n",
".PHONY: my_third_goal\n",
+ "$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))\n",
"$(call dist-for-goals,my_third_goal,one.out:test/dir/one.out)\n",
".PHONY: my_fourth_goal\n",
+ "$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))\n",
"$(call dist-for-goals,my_fourth_goal,one.out:one.suffix.out)\n",
".PHONY: my_fifth_goal\n",
+ "$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))\n",
"$(call dist-for-goals,my_fifth_goal,one.out:new-name)\n",
".PHONY: my_sixth_goal\n",
+ "$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))\n",
"$(call dist-for-goals,my_sixth_goal,one.out:some/dir/new-name.suffix)\n",
".PHONY: my_goal my_other_goal\n",
+ "$(if $(strip $(ALL_TARGETS.two.out.META_LIC)),,$(eval ALL_TARGETS.two.out.META_LIC := meta_lic))\n",
"$(call dist-for-goals,my_goal my_other_goal,two.out:two.out)\n",
+ "$(if $(strip $(ALL_TARGETS.three/four.out.META_LIC)),,$(eval ALL_TARGETS.three/four.out.META_LIC := meta_lic))\n",
"$(call dist-for-goals,my_goal my_other_goal,three/four.out:four.out)\n",
}
@@ -274,7 +287,7 @@
)
}
for idx, line := range androidMkLines {
- expectedLine := expectedAndroidMkLines[idx]
+ expectedLine := strings.ReplaceAll(expectedAndroidMkLines[idx], "meta_lic", module.base().licenseMetadataFile.String())
if line != expectedLine {
t.Errorf(
"Expected AndroidMk line to be '%s', got '%s'",
diff --git a/android/gen_notice.go b/android/gen_notice.go
new file mode 100644
index 0000000..e2b839f
--- /dev/null
+++ b/android/gen_notice.go
@@ -0,0 +1,212 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/google/blueprint/proptools"
+)
+
+func init() {
+ RegisterGenNoticeBuildComponents(InitRegistrationContext)
+}
+
+// Register the gen_notice module type.
+func RegisterGenNoticeBuildComponents(ctx RegistrationContext) {
+ ctx.RegisterSingletonType("gen_notice_build_rules", GenNoticeBuildRulesFactory)
+ ctx.RegisterModuleType("gen_notice", GenNoticeFactory)
+}
+
+type genNoticeBuildRules struct{}
+
+func (s *genNoticeBuildRules) GenerateBuildActions(ctx SingletonContext) {
+ ctx.VisitAllModules(func(m Module) {
+ gm, ok := m.(*genNoticeModule)
+ if !ok {
+ return
+ }
+ if len(gm.missing) > 0 {
+ missingReferencesRule(ctx, gm)
+ return
+ }
+ out := BuildNoticeTextOutputFromLicenseMetadata
+ if proptools.Bool(gm.properties.Xml) {
+ out = BuildNoticeXmlOutputFromLicenseMetadata
+ } else if proptools.Bool(gm.properties.Html) {
+ out = BuildNoticeHtmlOutputFromLicenseMetadata
+ }
+ defaultName := ""
+ if len(gm.properties.For) > 0 {
+ defaultName = gm.properties.For[0]
+ }
+
+ modules := make([]Module, 0)
+ for _, name := range gm.properties.For {
+ mods := ctx.ModuleVariantsFromName(gm, name)
+ for _, mod := range mods {
+ if mod == nil {
+ continue
+ }
+ modules = append(modules, mod)
+ }
+ }
+ if ctx.Failed() {
+ return
+ }
+ out(ctx, gm.output, ctx.ModuleName(gm),
+ proptools.StringDefault(gm.properties.ArtifactName, defaultName),
+ []string{
+ ctx.Config().OutDir() + "/",
+ ctx.Config().SoongOutDir() + "/",
+ }, modules...)
+ })
+}
+
+func GenNoticeBuildRulesFactory() Singleton {
+ return &genNoticeBuildRules{}
+}
+
+type genNoticeProperties struct {
+ // For specifies the modules for which to generate a notice file.
+ For []string
+ // ArtifactName specifies the internal name to use for the notice file.
+ // It appears in the "used by:" list for targets whose entire name is stripped by --strip_prefix.
+ ArtifactName *string
+ // Stem specifies the base name of the output file.
+ Stem *string `android:"arch_variant"`
+ // Html indicates an html-format file is needed. The default is text. Can be Html or Xml but not both.
+ Html *bool
+ // Xml indicates an xml-format file is needed. The default is text. Can be Html or Xml but not both.
+ Xml *bool
+ // Gzipped indicates the output file must be compressed with gzip. Will append .gz to suffix if not there.
+ Gzipped *bool
+ // Suffix specifies the file extension to use. Defaults to .html for html, .xml for xml, or no extension for text.
+ Suffix *string
+ // Visibility specifies where this license can be used
+ Visibility []string
+}
+
+type genNoticeModule struct {
+ ModuleBase
+ DefaultableModuleBase
+
+ properties genNoticeProperties
+
+ output OutputPath
+ missing []string
+}
+
+func (m *genNoticeModule) DepsMutator(ctx BottomUpMutatorContext) {
+ if proptools.Bool(m.properties.Html) && proptools.Bool(m.properties.Xml) {
+ ctx.ModuleErrorf("can be html or xml but not both")
+ }
+ if !ctx.Config().AllowMissingDependencies() {
+ var missing []string
+ // Verify the modules for which to generate notices exist.
+ for _, otherMod := range m.properties.For {
+ if !ctx.OtherModuleExists(otherMod) {
+ missing = append(missing, otherMod)
+ }
+ }
+ if len(missing) == 1 {
+ ctx.PropertyErrorf("for", "no %q module exists", missing[0])
+ } else if len(missing) > 1 {
+ ctx.PropertyErrorf("for", "modules \"%s\" do not exist", strings.Join(missing, "\", \""))
+ }
+ }
+}
+
+func (m *genNoticeModule) getStem() string {
+ stem := m.base().BaseModuleName()
+ if m.properties.Stem != nil {
+ stem = proptools.String(m.properties.Stem)
+ }
+ return stem
+}
+
+func (m *genNoticeModule) getSuffix() string {
+ suffix := ""
+ if m.properties.Suffix == nil {
+ if proptools.Bool(m.properties.Html) {
+ suffix = ".html"
+ } else if proptools.Bool(m.properties.Xml) {
+ suffix = ".xml"
+ }
+ } else {
+ suffix = proptools.String(m.properties.Suffix)
+ }
+ if proptools.Bool(m.properties.Gzipped) && !strings.HasSuffix(suffix, ".gz") {
+ suffix += ".gz"
+ }
+ return suffix
+}
+
+func (m *genNoticeModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+ if ctx.Config().AllowMissingDependencies() {
+ // Verify the modules for which to generate notices exist.
+ for _, otherMod := range m.properties.For {
+ if !ctx.OtherModuleExists(otherMod) {
+ m.missing = append(m.missing, otherMod)
+ }
+ }
+ m.missing = append(m.missing, ctx.GetMissingDependencies()...)
+ m.missing = FirstUniqueStrings(m.missing)
+ }
+ out := m.getStem() + m.getSuffix()
+ m.output = PathForModuleOut(ctx, out).OutputPath
+}
+
+func GenNoticeFactory() Module {
+ module := &genNoticeModule{}
+
+ base := module.base()
+ module.AddProperties(&base.nameProperties, &module.properties)
+
+ // The visibility property needs to be checked and parsed by the visibility module.
+ setPrimaryVisibilityProperty(module, "visibility", &module.properties.Visibility)
+
+ initAndroidModuleBase(module)
+ InitDefaultableModule(module)
+
+ return module
+}
+
+var _ OutputFileProducer = (*genNoticeModule)(nil)
+
+// Implements OutputFileProducer
+func (m *genNoticeModule) OutputFiles(tag string) (Paths, error) {
+ if tag == "" {
+ return Paths{m.output}, nil
+ }
+ return nil, fmt.Errorf("unrecognized tag %q", tag)
+}
+
+// missingReferencesRule emits an ErrorRule for missing module references.
+func missingReferencesRule(ctx BuilderContext, m *genNoticeModule) {
+ if len(m.missing) < 1 {
+ panic(fmt.Errorf("missing references rule requested with no missing references"))
+ }
+
+ ctx.Build(pctx, BuildParams{
+ Rule: ErrorRule,
+ Output: m.output,
+ Description: "notice for " + proptools.StringDefault(m.properties.ArtifactName, "container"),
+ Args: map[string]string{
+ "error": m.Name() + " references missing module(s): " + strings.Join(m.missing, ", "),
+ },
+ })
+}
diff --git a/android/gen_notice_test.go b/android/gen_notice_test.go
new file mode 100644
index 0000000..4ad2ecf
--- /dev/null
+++ b/android/gen_notice_test.go
@@ -0,0 +1,164 @@
+package android
+
+import (
+ "testing"
+
+ "github.com/google/blueprint"
+)
+
+var genNoticeTests = []struct {
+ name string
+ fs MockFS
+ expectedErrors []string
+}{
+ {
+ name: "gen_notice must not accept licenses property",
+ fs: map[string][]byte{
+ "top/Android.bp": []byte(`
+ gen_notice {
+ name: "top_license",
+ licenses: ["other_license"],
+ }`),
+ },
+ expectedErrors: []string{
+ `unrecognized property "licenses"`,
+ },
+ },
+ {
+ name: "bad gen_notice",
+ fs: map[string][]byte{
+ "top/Android.bp": []byte(`
+ gen_notice {
+ name: "top_notice",
+ for: ["top_rule"],
+ }`),
+ "other/Android.bp": []byte(`
+ mock_genrule {
+ name: "other_rule",
+ dep: ["top_notice"],
+ }`),
+ },
+ expectedErrors: []string{
+ `module "top_notice": for: no "top_rule" module exists`,
+ },
+ },
+ {
+ name: "doubly bad gen_notice",
+ fs: map[string][]byte{
+ "top/Android.bp": []byte(`
+ gen_notice {
+ name: "top_notice",
+ for: ["top_rule", "other_rule"],
+ }`),
+ },
+ expectedErrors: []string{
+ `module "top_notice": for: modules "top_rule", "other_rule" do not exist`,
+ },
+ },
+ {
+ name: "good gen_notice",
+ fs: map[string][]byte{
+ "top/Android.bp": []byte(`
+ gen_notice {
+ name: "top_notice",
+ for: ["top_rule"],
+ }
+
+ mock_genrule {
+ name: "top_rule",
+ dep: ["top_notice"],
+ }`),
+ "other/Android.bp": []byte(`
+ mock_genrule {
+ name: "other_rule",
+ dep: ["top_notice"],
+ }`),
+ },
+ },
+ {
+ name: "multiple license kinds",
+ fs: map[string][]byte{
+ "top/Android.bp": []byte(`
+ gen_notice {
+ name: "top_notice",
+ for: ["top_rule"],
+ }
+
+ gen_notice {
+ name: "top_html_notice",
+ html: true,
+ for: ["top_rule"],
+ }
+
+ gen_notice {
+ name: "top_xml_notice",
+ xml: true,
+ for: ["top_notice"],
+ }
+
+ mock_genrule {
+ name: "top_rule",
+ dep: [
+ "top_notice",
+ "top_html_notice",
+ "top_xml_notice",
+ ],
+ }`),
+ "other/Android.bp": []byte(`
+ mock_genrule {
+ name: "other_rule",
+ dep: ["top_xml_notice"],
+ }`),
+ },
+ },
+}
+
+func TestGenNotice(t *testing.T) {
+ for _, test := range genNoticeTests {
+ t.Run(test.name, func(t *testing.T) {
+ GroupFixturePreparers(
+ PrepareForTestWithGenNotice,
+ FixtureRegisterWithContext(func(ctx RegistrationContext) {
+ ctx.RegisterModuleType("mock_genrule", newMockGenruleModule)
+ }),
+ test.fs.AddToFixture(),
+ ).
+ ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(test.expectedErrors)).
+ RunTest(t)
+ })
+ }
+}
+
+type mockGenruleProperties struct {
+ Dep []string
+}
+
+type mockGenruleModule struct {
+ ModuleBase
+ DefaultableModuleBase
+
+ properties mockGenruleProperties
+}
+
+func newMockGenruleModule() Module {
+ m := &mockGenruleModule{}
+ m.AddProperties(&m.properties)
+ InitAndroidArchModule(m, HostAndDeviceSupported, MultilibCommon)
+ InitDefaultableModule(m)
+ return m
+}
+
+type genruleDepTag struct {
+ blueprint.BaseDependencyTag
+}
+
+func (j *mockGenruleModule) DepsMutator(ctx BottomUpMutatorContext) {
+ m, ok := ctx.Module().(Module)
+ if !ok {
+ return
+ }
+ ctx.AddDependency(m, genruleDepTag{}, j.properties.Dep...)
+}
+
+func (p *mockGenruleModule) GenerateAndroidBuildActions(ModuleContext) {
+}
diff --git a/android/license_metadata.go b/android/license_metadata.go
index 48c1383..f2ab0a4 100644
--- a/android/license_metadata.go
+++ b/android/license_metadata.go
@@ -105,7 +105,7 @@
if p := base.commonProperties.Effective_package_name; p != nil {
args = append(args,
- `-p "`+proptools.NinjaAndShellEscape(*p)+`"`)
+ `-p `+proptools.NinjaAndShellEscapeIncludingSpaces(*p))
}
args = append(args,
diff --git a/android/licenses.go b/android/licenses.go
index bd14b26..c47b3e6 100644
--- a/android/licenses.go
+++ b/android/licenses.go
@@ -303,6 +303,7 @@
switch reflect.TypeOf(module).String() {
case "*android.licenseModule": // is a license, doesn't need one
case "*android.licenseKindModule": // is a license, doesn't need one
+ case "*android.genNoticeModule": // contains license texts as data
case "*android.NamespaceModule": // just partitions things, doesn't add anything
case "*android.soongConfigModuleTypeModule": // creates aliases for modules with licenses
case "*android.soongConfigModuleTypeImport": // creates aliases for modules with licenses
@@ -330,6 +331,8 @@
func licensesMakeVarsProvider(ctx MakeVarsContext) {
ctx.Strict("BUILD_LICENSE_METADATA",
ctx.Config().HostToolPath(ctx, "build_license_metadata").String())
+ ctx.Strict("COPY_LICENSE_METADATA",
+ ctx.Config().HostToolPath(ctx, "copy_license_metadata").String())
ctx.Strict("HTMLNOTICE", ctx.Config().HostToolPath(ctx, "htmlnotice").String())
ctx.Strict("XMLNOTICE", ctx.Config().HostToolPath(ctx, "xmlnotice").String())
ctx.Strict("TEXTNOTICE", ctx.Config().HostToolPath(ctx, "textnotice").String())
diff --git a/android/module.go b/android/module.go
index 7285a2f..6f27f79 100644
--- a/android/module.go
+++ b/android/module.go
@@ -2260,14 +2260,6 @@
}
if optPath.Valid() {
m.noticeFiles = append(m.noticeFiles, optPath.Path())
- } else {
- for _, notice = range []string{"LICENSE", "LICENCE", "NOTICE"} {
- noticePath := filepath.Join(ctx.ModuleDir(), notice)
- optPath = ExistentPathForSource(ctx, noticePath)
- if optPath.Valid() {
- m.noticeFiles = append(m.noticeFiles, optPath.Path())
- }
- }
}
licensesPropertyFlattener(ctx)
diff --git a/android/singleton.go b/android/singleton.go
index 7ff96c9..7c6cf4f 100644
--- a/android/singleton.go
+++ b/android/singleton.go
@@ -29,6 +29,10 @@
ModuleType(module blueprint.Module) string
BlueprintFile(module blueprint.Module) string
+ // ModuleVariantsFromName returns the list of module variants named `name` in the same namespace as `referer` enforcing visibility rules.
+ // Allows generating build actions for `referer` based on the metadata for `name` deferred until the singleton context.
+ ModuleVariantsFromName(referer Module, name string) []Module
+
// ModuleProvider returns the value, if any, for the provider for a module. If the value for the
// provider was not set it returns the zero value of the type of the provider, which means the
// return value can always be type-asserted to the type of the provider. The return value should
@@ -251,3 +255,30 @@
func (s *singletonContextAdaptor) FinalModule(module Module) Module {
return s.SingletonContext.FinalModule(module).(Module)
}
+
+func (s *singletonContextAdaptor) ModuleVariantsFromName(referer Module, name string) []Module {
+ // get qualified module name for visibility enforcement
+ qualified := createQualifiedModuleName(s.ModuleName(referer), s.ModuleDir(referer))
+
+ modules := s.SingletonContext.ModuleVariantsFromName(referer, name)
+ result := make([]Module, 0, len(modules))
+ for _, m := range modules {
+ if module, ok := m.(Module); ok {
+ // enforce visibility
+ depName := s.ModuleName(module)
+ depDir := s.ModuleDir(module)
+ depQualified := qualifiedModuleName{depDir, depName}
+ // Targets are always visible to other targets in their own package.
+ if depQualified.pkg != qualified.pkg {
+ rule := effectiveVisibilityRules(s.Config(), depQualified)
+ if !rule.matches(qualified) {
+ s.ModuleErrorf(referer, "module %q references %q which is not visible to this module\nYou may need to add %q to its visibility",
+ referer.Name(), depQualified, "//"+s.ModuleDir(referer))
+ continue
+ }
+ }
+ result = append(result, module)
+ }
+ }
+ return result
+}
diff --git a/android/testing.go b/android/testing.go
index ac02db9..85bdca4 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -83,6 +83,8 @@
FixtureRegisterWithContext(registerLicenseMutators),
)
+var PrepareForTestWithGenNotice = FixtureRegisterWithContext(RegisterGenNoticeBuildComponents)
+
func registerLicenseMutators(ctx RegistrationContext) {
ctx.PreArchMutators(RegisterLicensesPackageMapper)
ctx.PreArchMutators(RegisterLicensesPropertyGatherer)
diff --git a/android/visibility.go b/android/visibility.go
index 5d1be6b..b209599 100644
--- a/android/visibility.go
+++ b/android/visibility.go
@@ -234,7 +234,7 @@
// Checks the per-module visibility rule lists before defaults expansion.
func visibilityRuleChecker(ctx BottomUpMutatorContext) {
- qualified := createQualifiedModuleName(ctx)
+ qualified := createQualifiedModuleName(ctx.ModuleName(), ctx.ModuleDir())
if m, ok := ctx.Module().(Module); ok {
visibilityProperties := m.visibilityProperties()
for _, p := range visibilityProperties {
@@ -435,7 +435,7 @@
return
}
- qualified := createQualifiedModuleName(ctx)
+ qualified := createQualifiedModuleName(ctx.ModuleName(), ctx.ModuleDir())
// Visit all the dependencies making sure that this module has access to them all.
ctx.VisitDirectDeps(func(dep Module) {
@@ -486,9 +486,7 @@
return rule
}
-func createQualifiedModuleName(ctx BaseModuleContext) qualifiedModuleName {
- moduleName := ctx.ModuleName()
- dir := ctx.ModuleDir()
+func createQualifiedModuleName(moduleName, dir string) qualifiedModuleName {
qualified := qualifiedModuleName{dir, moduleName}
return qualified
}
diff --git a/android/visibility_test.go b/android/visibility_test.go
index 714c92a..a66f0b6 100644
--- a/android/visibility_test.go
+++ b/android/visibility_test.go
@@ -135,7 +135,49 @@
name: "libexample",
visibility: ["//visibility:public"],
}
-
+
+ mock_library {
+ name: "libsamepackage",
+ deps: ["libexample"],
+ }
+
+ gen_notice {
+ name: "libexample-notice",
+ for: ["libexample"],
+ }`),
+ "top/nested/Android.bp": []byte(`
+ mock_library {
+ name: "libnested",
+ deps: ["libexample"],
+ }
+
+ gen_notice {
+ name: "nested-notice",
+ for: ["libexample"],
+ }`),
+ "other/Android.bp": []byte(`
+ mock_library {
+ name: "libother",
+ deps: ["libexample"],
+ }
+
+ gen_notice {
+ name: "other-notice",
+ for: ["libexample"],
+ }`),
+ },
+ },
+ {
+ // Verify that //visibility:private allows the module to be referenced from the current
+ // directory only.
+ name: "//visibility:private",
+ fs: MockFS{
+ "top/Android.bp": []byte(`
+ mock_library {
+ name: "libexample",
+ visibility: ["//visibility:private"],
+ }
+
mock_library {
name: "libsamepackage",
deps: ["libexample"],
@@ -151,18 +193,61 @@
deps: ["libexample"],
}`),
},
+ expectedErrors: []string{
+ `module "libnested" variant "android_common": depends on //top:libexample which is not` +
+ ` visible to this module`,
+ `module "libother" variant "android_common": depends on //top:libexample which is not` +
+ ` visible to this module`,
+ },
},
{
// Verify that //visibility:private allows the module to be referenced from the current
// directory only.
- name: "//visibility:private",
+ name: "//visibility:private (notices)",
fs: MockFS{
"top/Android.bp": []byte(`
mock_library {
name: "libexample",
visibility: ["//visibility:private"],
}
-
+
+ mock_library {
+ name: "libsamepackage",
+ deps: ["libexample"],
+ }
+
+ gen_notice {
+ name: "libexample-notice",
+ for: ["libexample"],
+ }`),
+ "top/nested/Android.bp": []byte(`
+ gen_notice {
+ name: "nested-notice",
+ for: ["libexample"],
+ }`),
+ "other/Android.bp": []byte(`
+ gen_notice {
+ name: "other-notice",
+ for: ["libexample"],
+ }`),
+ },
+ expectedErrors: []string{
+ `module "nested-notice" references "//top:libexample" which is not visible to this` +
+ ` module\nYou may need to add "//top/nested" to its visibility`,
+ `module "other-notice" references "//top:libexample" which is not visible to this module\n` +
+ `You may need to add "//other" to its visibility`,
+ },
+ },
+ {
+ // Verify that :__pkg__ allows the module to be referenced from the current directory only.
+ name: ":__pkg__",
+ fs: MockFS{
+ "top/Android.bp": []byte(`
+ mock_library {
+ name: "libexample",
+ visibility: [":__pkg__"],
+ }
+
mock_library {
name: "libsamepackage",
deps: ["libexample"],
@@ -187,34 +272,32 @@
},
{
// Verify that :__pkg__ allows the module to be referenced from the current directory only.
- name: ":__pkg__",
+ name: ":__pkg__ (notices)",
fs: MockFS{
"top/Android.bp": []byte(`
mock_library {
name: "libexample",
visibility: [":__pkg__"],
}
-
- mock_library {
- name: "libsamepackage",
- deps: ["libexample"],
+
+ gen_notice {
+ name: "libexample-notice",
+ for: ["libexample"],
}`),
"top/nested/Android.bp": []byte(`
- mock_library {
- name: "libnested",
- deps: ["libexample"],
+ gen_notice {
+ name: "nested-notice",
+ for: ["libexample"],
}`),
"other/Android.bp": []byte(`
- mock_library {
- name: "libother",
- deps: ["libexample"],
+ gen_notice {
+ name: "other-notice",
+ for: ["libexample"],
}`),
},
expectedErrors: []string{
- `module "libnested" variant "android_common": depends on //top:libexample which is not` +
- ` visible to this module`,
- `module "libother" variant "android_common": depends on //top:libexample which is not` +
- ` visible to this module`,
+ `module "nested-notice" references "//top:libexample" which is not visible to this module`,
+ `module "other-notice" references "//top:libexample" which is not visible to this module`,
},
},
{
@@ -227,7 +310,7 @@
name: "libexample",
visibility: ["//top/nested"],
}
-
+
mock_library {
name: "libsamepackage",
deps: ["libexample"],
@@ -256,6 +339,42 @@
},
},
{
+ // Verify that //top/nested allows the module to be referenced from the current directory and
+ // the top/nested directory only, not a subdirectory of top/nested and not peak directory.
+ name: "//top/nested (notices)",
+ fs: MockFS{
+ "top/Android.bp": []byte(`
+ mock_library {
+ name: "libexample",
+ visibility: ["//top/nested"],
+ }
+
+ gen_notice {
+ name: "libexample-notice",
+ for: ["libexample"],
+ }`),
+ "top/nested/Android.bp": []byte(`
+ gen_notice {
+ name: "nested-notice",
+ for: ["libexample"],
+ }`),
+ "top/nested/again/Android.bp": []byte(`
+ gen_notice {
+ name: "nestedagain-notice",
+ for: ["libexample"],
+ }`),
+ "peak/Android.bp": []byte(`
+ gen_notice {
+ name: "other-notice",
+ for: ["libexample"],
+ }`),
+ },
+ expectedErrors: []string{
+ `module "other-notice" references "//top:libexample" which is not visible to this module`,
+ `module "nestedagain-notice" references "//top:libexample" which is not visible to this module`,
+ },
+ },
+ {
// Verify that :__subpackages__ allows the module to be referenced from the current directory
// and sub directories but nowhere else.
name: ":__subpackages__",
@@ -265,7 +384,7 @@
name: "libexample",
visibility: [":__subpackages__"],
}
-
+
mock_library {
name: "libsamepackage",
deps: ["libexample"],
@@ -287,6 +406,36 @@
},
},
{
+ // Verify that :__subpackages__ allows the module to be referenced from the current directory
+ // and sub directories but nowhere else.
+ name: ":__subpackages__ (notices)",
+ fs: MockFS{
+ "top/Android.bp": []byte(`
+ mock_library {
+ name: "libexample",
+ visibility: [":__subpackages__"],
+ }
+
+ gen_notice {
+ name: "libexample-notice",
+ for: ["libexample"],
+ }`),
+ "top/nested/Android.bp": []byte(`
+ gen_notice {
+ name: "nested-notice",
+ for: ["libexample"],
+ }`),
+ "peak/other/Android.bp": []byte(`
+ gen_notice {
+ name: "other-notice",
+ for: ["libexample"],
+ }`),
+ },
+ expectedErrors: []string{
+ `module "other-notice" references "//top:libexample" which is not visible to this module`,
+ },
+ },
+ {
// Verify that //top/nested:__subpackages__ allows the module to be referenced from the current
// directory and sub directories but nowhere else.
name: "//top/nested:__subpackages__",
@@ -296,7 +445,7 @@
name: "libexample",
visibility: ["//top/nested:__subpackages__", "//other"],
}
-
+
mock_library {
name: "libsamepackage",
deps: ["libexample"],
@@ -318,6 +467,36 @@
},
},
{
+ // Verify that //top/nested:__subpackages__ allows the module to be referenced from the current
+ // directory and sub directories but nowhere else.
+ name: "//top/nested:__subpackages__ (notices)",
+ fs: MockFS{
+ "top/Android.bp": []byte(`
+ mock_library {
+ name: "libexample",
+ visibility: ["//top/nested:__subpackages__", "//other"],
+ }
+
+ gen_notice {
+ name: "libexample-notice",
+ for: ["libexample"],
+ }`),
+ "top/nested/Android.bp": []byte(`
+ gen_notice {
+ name: "nested-notice",
+ for: ["libexample"],
+ }`),
+ "top/other/Android.bp": []byte(`
+ gen_notice {
+ name: "other-notice",
+ for: ["libexample"],
+ }`),
+ },
+ expectedErrors: []string{
+ `module "other-notice" references "//top:libexample" which is not visible to this module`,
+ },
+ },
+ {
// Verify that ["//top/nested", "//peak:__subpackages"] allows the module to be referenced from
// the current directory, top/nested and peak and all its subpackages.
name: `["//top/nested", "//peak:__subpackages__"]`,
@@ -327,7 +506,7 @@
name: "libexample",
visibility: ["//top/nested", "//peak:__subpackages__"],
}
-
+
mock_library {
name: "libsamepackage",
deps: ["libexample"],
@@ -345,6 +524,33 @@
},
},
{
+ // Verify that ["//top/nested", "//peak:__subpackages"] allows the module to be referenced from
+ // the current directory, top/nested and peak and all its subpackages.
+ name: `["//top/nested", "//peak:__subpackages__ (notices)"]`,
+ fs: MockFS{
+ "top/Android.bp": []byte(`
+ mock_library {
+ name: "libexample",
+ visibility: ["//top/nested", "//peak:__subpackages__"],
+ }
+
+ gen_notice {
+ name: "libexample-notice",
+ for: ["libexample"],
+ }`),
+ "top/nested/Android.bp": []byte(`
+ gen_notice {
+ name: "nested-notice",
+ for: ["libexample"],
+ }`),
+ "peak/other/Android.bp": []byte(`
+ gen_notice {
+ name: "other-notice",
+ for: ["libexample"],
+ }`),
+ },
+ },
+ {
// Verify that //vendor... cannot be used outside vendor apart from //vendor:__subpackages__
name: `//vendor`,
fs: MockFS{
@@ -353,7 +559,7 @@
name: "libexample",
visibility: ["//vendor:__subpackages__"],
}
-
+
mock_library {
name: "libsamepackage",
visibility: ["//vendor/apps/AcmeSettings"],
@@ -418,6 +624,45 @@
},
},
{
+ // Check that visibility is the union of the defaults modules.
+ name: "defaults union, basic (notices)",
+ fs: MockFS{
+ "top/Android.bp": []byte(`
+ mock_defaults {
+ name: "libexample_defaults",
+ visibility: ["//other"],
+ }
+ mock_library {
+ name: "libexample",
+ visibility: ["//top/nested"],
+ defaults: ["libexample_defaults"],
+ }
+
+ gen_notice {
+ name: "libexample-notice",
+ for: ["libexample"],
+ }`),
+ "top/nested/Android.bp": []byte(`
+ gen_notice {
+ name: "nested-notice",
+ for: ["libexample"],
+ }`),
+ "other/Android.bp": []byte(`
+ gen_notice {
+ name: "other-notice",
+ for: ["libexample"],
+ }`),
+ "outsider/Android.bp": []byte(`
+ gen_notice {
+ name: "outsider-notice",
+ for: ["libexample"],
+ }`),
+ },
+ expectedErrors: []string{
+ `module "outsider-notice" references "//top:libexample" which is not visible to this module`,
+ },
+ },
+ {
name: "defaults union, multiple defaults",
fs: MockFS{
"top/Android.bp": []byte(`
@@ -459,6 +704,47 @@
},
},
{
+ name: "defaults union, multiple defaults (notices)",
+ fs: MockFS{
+ "top/Android.bp": []byte(`
+ mock_defaults {
+ name: "libexample_defaults_1",
+ visibility: ["//other"],
+ }
+ mock_defaults {
+ name: "libexample_defaults_2",
+ visibility: ["//top/nested"],
+ }
+ mock_library {
+ name: "libexample",
+ defaults: ["libexample_defaults_1", "libexample_defaults_2"],
+ }
+
+ gen_notice {
+ name: "libexample-notice",
+ for: ["libexample"],
+ }`),
+ "top/nested/Android.bp": []byte(`
+ gen_notice {
+ name: "nested-notice",
+ for: ["libexample"],
+ }`),
+ "other/Android.bp": []byte(`
+ gen_notice {
+ name: "other-notice",
+ for: ["libexample"],
+ }`),
+ "outsider/Android.bp": []byte(`
+ gen_notice {
+ name: "outsider-notice",
+ for: ["libexample"],
+ }`),
+ },
+ expectedErrors: []string{
+ `module "outsider-notice" references "//top:libexample" which is not visible to this module`,
+ },
+ },
+ {
name: "//visibility:public mixed with other in defaults",
fs: MockFS{
"top/Android.bp": []byte(`
@@ -500,6 +786,29 @@
},
},
{
+ name: "//visibility:public overriding defaults (notices)",
+ fs: MockFS{
+ "top/Android.bp": []byte(`
+ mock_defaults {
+ name: "libexample_defaults",
+ visibility: ["//namespace"],
+ }
+ mock_library {
+ name: "libexample",
+ visibility: ["//visibility:public"],
+ defaults: ["libexample_defaults"],
+ }`),
+ "outsider/Android.bp": []byte(`
+ gen_notice {
+ name: "outsider-notice",
+ for: ["libexample"],
+ }`),
+ },
+ effectiveVisibility: map[qualifiedModuleName][]string{
+ qualifiedModuleName{pkg: "top", name: "libexample"}: {"//visibility:public"},
+ },
+ },
+ {
name: "//visibility:public mixed with other from different defaults 1",
fs: MockFS{
"top/Android.bp": []byte(`
@@ -523,6 +832,34 @@
},
},
{
+ name: "//visibility:public mixed with other from different defaults 1",
+ fs: MockFS{
+ "top/Android.bp": []byte(`
+ mock_defaults {
+ name: "libexample_defaults_1",
+ visibility: ["//namespace"],
+ }
+ mock_defaults {
+ name: "libexample_defaults_2",
+ visibility: ["//visibility:public"],
+ }
+ mock_library {
+ name: "libexample",
+ defaults: ["libexample_defaults_1", "libexample_defaults_2"],
+ }
+
+ gen_notice {
+ name: "libexample-notice",
+ for: ["libexample"],
+ }`),
+ "outsider/Android.bp": []byte(`
+ gen_notice {
+ name: "outsider-notice",
+ for: ["libexample"],
+ }`),
+ },
+ },
+ {
name: "//visibility:public mixed with other from different defaults 2",
fs: MockFS{
"top/Android.bp": []byte(`
@@ -546,6 +883,29 @@
},
},
{
+ name: "//visibility:public mixed with other from different defaults 2 (notices)",
+ fs: MockFS{
+ "top/Android.bp": []byte(`
+ mock_defaults {
+ name: "libexample_defaults_1",
+ visibility: ["//visibility:public"],
+ }
+ mock_defaults {
+ name: "libexample_defaults_2",
+ visibility: ["//namespace"],
+ }
+ mock_library {
+ name: "libexample",
+ defaults: ["libexample_defaults_1", "libexample_defaults_2"],
+ }`),
+ "outsider/Android.bp": []byte(`
+ gen_notice {
+ name: "outsider-notice",
+ for: ["libexample"],
+ }`),
+ },
+ },
+ {
name: "//visibility:private in defaults",
fs: MockFS{
"top/Android.bp": []byte(`
@@ -580,6 +940,39 @@
},
},
{
+ name: "//visibility:private in defaults (notices)",
+ fs: MockFS{
+ "top/Android.bp": []byte(`
+ mock_defaults {
+ name: "libexample_defaults",
+ visibility: ["//visibility:private"],
+ }
+ mock_library {
+ name: "libexample",
+ defaults: ["libexample_defaults"],
+ }
+
+ gen_notice {
+ name: "libexample-notice",
+ for: ["libexample"],
+ }`),
+ "top/nested/Android.bp": []byte(`
+ gen_notice {
+ name: "nested-notice",
+ for: ["libexample"],
+ }`),
+ "other/Android.bp": []byte(`
+ gen_notice {
+ name: "other-notice",
+ for: ["libexample"],
+ }`),
+ },
+ expectedErrors: []string{
+ `module "nested-notice" references "//top:libexample" which is not visible to this module`,
+ `module "other-notice" references "//top:libexample" which is not visible to this module`,
+ },
+ },
+ {
name: "//visibility:private mixed with other in defaults",
fs: MockFS{
"top/Android.bp": []byte(`
@@ -706,6 +1099,27 @@
},
},
{
+ name: "//visibility:override discards //visibility:private (notices)",
+ fs: MockFS{
+ "top/Android.bp": []byte(`
+ mock_defaults {
+ name: "libexample_defaults",
+ visibility: ["//visibility:private"],
+ }
+ mock_library {
+ name: "libexample",
+ // Make this visibility to //other but not //visibility:private
+ visibility: ["//visibility:override", "//other"],
+ defaults: ["libexample_defaults"],
+ }`),
+ "other/Android.bp": []byte(`
+ gen_notice {
+ name: "other-notice",
+ for: ["libexample"],
+ }`),
+ },
+ },
+ {
name: "//visibility:override discards //visibility:public",
fs: MockFS{
"top/Android.bp": []byte(`
@@ -735,6 +1149,35 @@
},
},
{
+ name: "//visibility:override discards //visibility:public (notices)",
+ fs: MockFS{
+ "top/Android.bp": []byte(`
+ mock_defaults {
+ name: "libexample_defaults",
+ visibility: ["//visibility:public"],
+ }
+ mock_library {
+ name: "libexample",
+ // Make this visibility to //other but not //visibility:public
+ visibility: ["//visibility:override", "//other"],
+ defaults: ["libexample_defaults"],
+ }`),
+ "other/Android.bp": []byte(`
+ gen_notice {
+ name: "other-notice",
+ for: ["libexample"],
+ }`),
+ "namespace/Android.bp": []byte(`
+ gen_notice {
+ name: "namespace-notice",
+ for: ["libexample"],
+ }`),
+ },
+ expectedErrors: []string{
+ `module "namespace-notice" references "//top:libexample" which is not visible to this module\nYou may need to add "//namespace" to its visibility`,
+ },
+ },
+ {
name: "//visibility:override discards defaults supplied rules",
fs: MockFS{
"top/Android.bp": []byte(`
@@ -764,6 +1207,35 @@
},
},
{
+ name: "//visibility:override discards defaults supplied rules (notices)",
+ fs: MockFS{
+ "top/Android.bp": []byte(`
+ mock_defaults {
+ name: "libexample_defaults",
+ visibility: ["//namespace"],
+ }
+ mock_library {
+ name: "libexample",
+ // Make this visibility to //other but not //namespace
+ visibility: ["//visibility:override", "//other"],
+ defaults: ["libexample_defaults"],
+ }`),
+ "other/Android.bp": []byte(`
+ gen_notice {
+ name: "other-notice",
+ for: ["libexample"],
+ }`),
+ "namespace/Android.bp": []byte(`
+ gen_notice {
+ name: "namespace-notice",
+ for: ["libexample"],
+ }`),
+ },
+ expectedErrors: []string{
+ `module "namespace-notice" references "//top:libexample" which is not visible to this module\nYou may need to add "//namespace" to its visibility`,
+ },
+ },
+ {
name: "//visibility:override can override //visibility:public with //visibility:private",
fs: MockFS{
"top/Android.bp": []byte(`
@@ -787,6 +1259,29 @@
},
},
{
+ name: "//visibility:override can override //visibility:public with //visibility:private (notices)",
+ fs: MockFS{
+ "top/Android.bp": []byte(`
+ mock_defaults {
+ name: "libexample_defaults",
+ visibility: ["//visibility:public"],
+ }
+ mock_library {
+ name: "libexample",
+ visibility: ["//visibility:override", "//visibility:private"],
+ defaults: ["libexample_defaults"],
+ }`),
+ "namespace/Android.bp": []byte(`
+ gen_notice {
+ name: "namespace-notice",
+ for: ["libexample"],
+ }`),
+ },
+ expectedErrors: []string{
+ `module "namespace-notice" references "//top:libexample" which is not visible to this module`,
+ },
+ },
+ {
name: "//visibility:override can override //visibility:private with //visibility:public",
fs: MockFS{
"top/Android.bp": []byte(`
@@ -807,6 +1302,26 @@
},
},
{
+ name: "//visibility:override can override //visibility:private with //visibility:public (notices)",
+ fs: MockFS{
+ "top/Android.bp": []byte(`
+ mock_defaults {
+ name: "libexample_defaults",
+ visibility: ["//visibility:private"],
+ }
+ mock_library {
+ name: "libexample",
+ visibility: ["//visibility:override", "//visibility:public"],
+ defaults: ["libexample_defaults"],
+ }`),
+ "namespace/Android.bp": []byte(`
+ gen_notice {
+ name: "namespace-notice",
+ for: ["libexample"],
+ }`),
+ },
+ },
+ {
name: "//visibility:private mixed with itself",
fs: MockFS{
"top/Android.bp": []byte(`
@@ -834,6 +1349,33 @@
` visible to this module`,
},
},
+ {
+ name: "//visibility:private mixed with itself (notices)",
+ fs: MockFS{
+ "top/Android.bp": []byte(`
+ mock_defaults {
+ name: "libexample_defaults_1",
+ visibility: ["//visibility:private"],
+ }
+ mock_defaults {
+ name: "libexample_defaults_2",
+ visibility: ["//visibility:private"],
+ }
+ mock_library {
+ name: "libexample",
+ visibility: ["//visibility:private"],
+ defaults: ["libexample_defaults_1", "libexample_defaults_2"],
+ }`),
+ "outsider/Android.bp": []byte(`
+ gen_notice {
+ name: "outsider-notice",
+ for: ["libexample"],
+ }`),
+ },
+ expectedErrors: []string{
+ `module "outsider-notice" references "//top:libexample" which is not visible to this module`,
+ },
+ },
// Defaults module's defaults_visibility tests
{
@@ -903,6 +1445,28 @@
},
},
{
+ // This test relies on the default visibility being legacy_public.
+ name: "package default_visibility property used when no visibility specified (notices)",
+ fs: MockFS{
+ "top/Android.bp": []byte(`
+ package {
+ default_visibility: ["//visibility:private"],
+ }
+
+ mock_library {
+ name: "libexample",
+ }`),
+ "outsider/Android.bp": []byte(`
+ gen_notice {
+ name: "outsider-notice",
+ for: ["libexample"],
+ }`),
+ },
+ expectedErrors: []string{
+ `module "outsider-notice" references "//top:libexample" which is not visible to this module`,
+ },
+ },
+ {
name: "package default_visibility public does not override visibility private",
fs: MockFS{
"top/Android.bp": []byte(`
@@ -926,6 +1490,28 @@
},
},
{
+ name: "package default_visibility public does not override visibility private (notices)",
+ fs: MockFS{
+ "top/Android.bp": []byte(`
+ package {
+ default_visibility: ["//visibility:public"],
+ }
+
+ mock_library {
+ name: "libexample",
+ visibility: ["//visibility:private"],
+ }`),
+ "outsider/Android.bp": []byte(`
+ gen_notice {
+ name: "outsider-notice",
+ for: ["libexample"],
+ }`),
+ },
+ expectedErrors: []string{
+ `module "outsider-notice" references "//top:libexample" which is not visible to this module`,
+ },
+ },
+ {
name: "package default_visibility private does not override visibility public",
fs: MockFS{
"top/Android.bp": []byte(`
@@ -945,6 +1531,25 @@
},
},
{
+ name: "package default_visibility private does not override visibility public (notices)",
+ fs: MockFS{
+ "top/Android.bp": []byte(`
+ package {
+ default_visibility: ["//visibility:private"],
+ }
+
+ mock_library {
+ name: "libexample",
+ visibility: ["//visibility:public"],
+ }`),
+ "outsider/Android.bp": []byte(`
+ gen_notice {
+ name: "outsider-notice",
+ for: ["libexample"],
+ }`),
+ },
+ },
+ {
name: "package default_visibility :__subpackages__",
fs: MockFS{
"top/Android.bp": []byte(`
@@ -972,6 +1577,32 @@
},
},
{
+ name: "package default_visibility :__subpackages__ (notices)",
+ fs: MockFS{
+ "top/Android.bp": []byte(`
+ package {
+ default_visibility: [":__subpackages__"],
+ }
+
+ mock_library {
+ name: "libexample",
+ }`),
+ "top/nested/Android.bp": []byte(`
+ gen_notice {
+ name: "nested-notice",
+ for: ["libexample"],
+ }`),
+ "outsider/Android.bp": []byte(`
+ gen_notice {
+ name: "outsider-notice",
+ for: ["libexample"],
+ }`),
+ },
+ expectedErrors: []string{
+ `module "outsider-notice" references "//top:libexample" which is not visible to this module`,
+ },
+ },
+ {
name: "package default_visibility inherited to subpackages",
fs: MockFS{
"top/Android.bp": []byte(`
@@ -981,7 +1612,7 @@
mock_library {
name: "libexample",
- visibility: [":__subpackages__"],
+ visibility: [":__subpackages__"],
}`),
"top/nested/Android.bp": []byte(`
mock_library {
@@ -1000,6 +1631,38 @@
},
},
{
+ name: "package default_visibility inherited to subpackages (notices)",
+ fs: MockFS{
+ "top/Android.bp": []byte(`
+ package {
+ default_visibility: ["//outsider"],
+ }
+
+ mock_library {
+ name: "libexample",
+ visibility: [":__subpackages__"],
+ }`),
+ "top/nested/Android.bp": []byte(`
+ mock_library {
+ name: "libnested",
+ deps: ["libexample"],
+ }
+
+ gen_notice {
+ name: "nested-notice",
+ for: ["libexample"],
+ }`),
+ "outsider/Android.bp": []byte(`
+ gen_notice {
+ name: "outsider-notice",
+ for: ["libexample", "libnested"],
+ }`),
+ },
+ expectedErrors: []string{
+ `module "outsider-notice" references "//top:libexample" which is not visible to this module`,
+ },
+ },
+ {
name: "package default_visibility inherited to subpackages",
fs: MockFS{
"top/Android.bp": []byte(`
@@ -1030,6 +1693,41 @@
},
},
{
+ name: "package default_visibility inherited to subpackages (notices)",
+ fs: MockFS{
+ "top/Android.bp": []byte(`
+ package {
+ default_visibility: ["//visibility:private"],
+ }`),
+ "top/nested/Android.bp": []byte(`
+ package {
+ default_visibility: ["//outsider"],
+ }
+
+ mock_library {
+ name: "libnested",
+ }`),
+ "top/other/Android.bp": []byte(`
+ mock_library {
+ name: "libother",
+ }
+
+ gen_notice {
+ name: "other-notice",
+ for: ["libother"],
+ }`),
+ "outsider/Android.bp": []byte(`
+ gen_notice {
+ name: "outsider-notice",
+ for: ["libother", "libnested"],
+ }`),
+ },
+ expectedErrors: []string{
+ `module "outsider-notice" references "//top/other:libother" which is not visible to this` +
+ ` module\nYou may need to add "//outsider" to its visibility`,
+ },
+ },
+ {
name: "verify that prebuilt dependencies are ignored for visibility reasons (not preferred)",
fs: MockFS{
"prebuilts/Android.bp": []byte(`
@@ -1052,6 +1750,28 @@
},
},
{
+ name: "verify that prebuilt dependencies are ignored for visibility reasons (not preferred) (notices)",
+ fs: MockFS{
+ "prebuilts/Android.bp": []byte(`
+ prebuilt {
+ name: "module",
+ visibility: ["//top/other"],
+ }`),
+ "top/sources/source_file": nil,
+ "top/sources/Android.bp": []byte(`
+ source {
+ name: "module",
+ visibility: ["//top/other"],
+ }`),
+ "top/other/source_file": nil,
+ "top/other/Android.bp": []byte(`
+ gen_notice {
+ name: "other-notice",
+ for: ["module"],
+ }`),
+ },
+ },
+ {
name: "verify that prebuilt dependencies are ignored for visibility reasons (preferred)",
fs: MockFS{
"prebuilts/Android.bp": []byte(`
@@ -1075,6 +1795,29 @@
},
},
{
+ name: "verify that prebuilt dependencies are ignored for visibility reasons (preferred) (notices)",
+ fs: MockFS{
+ "prebuilts/Android.bp": []byte(`
+ prebuilt {
+ name: "module",
+ visibility: ["//top/other"],
+ prefer: true,
+ }`),
+ "top/sources/source_file": nil,
+ "top/sources/Android.bp": []byte(`
+ source {
+ name: "module",
+ visibility: ["//top/other"],
+ }`),
+ "top/other/source_file": nil,
+ "top/other/Android.bp": []byte(`
+ gen_notice {
+ name: "other-notice",
+ for: ["module"],
+ }`),
+ },
+ },
+ {
name: "ensure visibility properties are checked for correctness",
fs: MockFS{
"top/Android.bp": []byte(`
@@ -1137,6 +1880,30 @@
}`),
},
},
+ {
+ name: "automatic visibility inheritance enabled (notices)",
+ fs: MockFS{
+ "top/Android.bp": []byte(`
+ mock_parent {
+ name: "parent",
+ visibility: ["//top/nested"],
+ child: {
+ name: "libchild",
+ visibility: ["//top/other"],
+ },
+ }`),
+ "top/nested/Android.bp": []byte(`
+ gen_notice {
+ name: "nested-notice",
+ for: ["libchild"],
+ }`),
+ "top/other/Android.bp": []byte(`
+ gen_notice {
+ name: "other-notice",
+ for: ["libchild"],
+ }`),
+ },
+ },
}
func TestVisibility(t *testing.T) {
@@ -1147,6 +1914,7 @@
// registration order.
PrepareForTestWithArchMutator,
PrepareForTestWithDefaults,
+ PrepareForTestWithGenNotice,
PrepareForTestWithOverrides,
PrepareForTestWithPackageModule,
PrepareForTestWithPrebuilts,
diff --git a/apex/androidmk.go b/apex/androidmk.go
index e094a12..938c8ed 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -412,6 +412,7 @@
fmt.Fprintln(w, ".PHONY:", goal)
fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s)\n",
goal, a.installedFilesFile.String(), distFile)
+ fmt.Fprintf(w, "$(call declare-0p-target,%s)\n", a.installedFilesFile.String())
}
for _, dist := range data.Entries.GetDistForGoals(a) {
fmt.Fprintf(w, dist)
diff --git a/compliance/copy_license_metadata/Android.bp b/compliance/copy_license_metadata/Android.bp
new file mode 100644
index 0000000..83019eb
--- /dev/null
+++ b/compliance/copy_license_metadata/Android.bp
@@ -0,0 +1,30 @@
+// Copyright 2022 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+blueprint_go_binary {
+ name: "copy_license_metadata",
+ srcs: [
+ "copy_license_metadata.go",
+ ],
+ deps: [
+ "license_metadata_proto",
+ "golang-protobuf-proto",
+ "golang-protobuf-encoding-prototext",
+ "soong-response",
+ ],
+}
diff --git a/compliance/copy_license_metadata/copy_license_metadata.go b/compliance/copy_license_metadata/copy_license_metadata.go
new file mode 100644
index 0000000..36b9489
--- /dev/null
+++ b/compliance/copy_license_metadata/copy_license_metadata.go
@@ -0,0 +1,144 @@
+// Copyright 2022 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "strings"
+
+ "google.golang.org/protobuf/encoding/prototext"
+ "google.golang.org/protobuf/proto"
+
+ "android/soong/compliance/license_metadata_proto"
+ "android/soong/response"
+)
+
+func newMultiString(flags *flag.FlagSet, name, usage string) *multiString {
+ var f multiString
+ flags.Var(&f, name, usage)
+ return &f
+}
+
+type multiString []string
+
+func (ms *multiString) String() string { return strings.Join(*ms, ", ") }
+func (ms *multiString) Set(s string) error { *ms = append(*ms, s); return nil }
+
+func main() {
+ var expandedArgs []string
+ for _, arg := range os.Args[1:] {
+ if strings.HasPrefix(arg, "@") {
+ f, err := os.Open(strings.TrimPrefix(arg, "@"))
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err.Error())
+ os.Exit(1)
+ }
+
+ respArgs, err := response.ReadRspFile(f)
+ f.Close()
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err.Error())
+ os.Exit(1)
+ }
+ expandedArgs = append(expandedArgs, respArgs...)
+ } else {
+ expandedArgs = append(expandedArgs, arg)
+ }
+ }
+
+ flags := flag.NewFlagSet("flags", flag.ExitOnError)
+
+ installed := flags.String("i", "", "installed target")
+ sources := newMultiString(flags, "s", "source (input) file")
+ dep := flags.String("d", "", "license metadata file dependency")
+ outFile := flags.String("o", "", "output file")
+
+ flags.Parse(expandedArgs)
+
+ if len(*dep) == 0 || len(*installed) == 0 || len(*sources) == 0 {
+ flags.Usage()
+ if len(*dep) == 0 {
+ fmt.Fprintf(os.Stderr, "source license metadata (-d flag) required\n")
+ }
+ if len(*sources) == 0 {
+ fmt.Fprintf(os.Stderr, "source copy (-s flag required\n")
+ }
+ if len(*installed) == 0 {
+ fmt.Fprintf(os.Stderr, "installed copy (-i flag) required\n")
+ }
+ os.Exit(1)
+ }
+
+ src_metadata := license_metadata_proto.LicenseMetadata{}
+ err := readMetadata(*dep, &src_metadata)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "error: %s\n", err.Error())
+ os.Exit(2)
+ }
+
+ metadata := src_metadata
+ metadata.Built = nil
+ metadata.InstallMap = nil
+ metadata.Installed = []string{*installed}
+ metadata.Sources = *sources
+ metadata.Deps = []*license_metadata_proto.AnnotatedDependency{&license_metadata_proto.AnnotatedDependency{
+ File: proto.String(*dep),
+ Annotations: []string{"static"},
+ }}
+
+ err = writeMetadata(*outFile, &metadata)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "error: %s\n", err.Error())
+ os.Exit(2)
+ }
+}
+
+func readMetadata(file string, metadata *license_metadata_proto.LicenseMetadata) error {
+ if file == "" {
+ return fmt.Errorf("source metadata file (-d) required")
+ }
+ buf, err := ioutil.ReadFile(file)
+ if err != nil {
+ return fmt.Errorf("error reading textproto %q: %w", file, err)
+ }
+
+ err = prototext.Unmarshal(buf, metadata)
+ if err != nil {
+ return fmt.Errorf("error unmarshalling textproto: %w", err)
+ }
+
+ return nil
+}
+
+func writeMetadata(file string, metadata *license_metadata_proto.LicenseMetadata) error {
+ buf, err := prototext.MarshalOptions{Multiline: true}.Marshal(metadata)
+ if err != nil {
+ return fmt.Errorf("error marshalling textproto: %w", err)
+ }
+
+ if file != "" {
+ err = ioutil.WriteFile(file, buf, 0666)
+ if err != nil {
+ return fmt.Errorf("error writing textproto %q: %w", file, err)
+ }
+ } else {
+ _, _ = os.Stdout.Write(buf)
+ }
+
+ return nil
+}
diff --git a/java/android_manifest.go b/java/android_manifest.go
index 7772b70..1553564 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -45,7 +45,11 @@
// This enables release builds (that run with TARGET_BUILD_APPS=[val...]) to target APIs that have not yet been finalized as part of an SDK
func targetSdkVersionForManifestFixer(ctx android.ModuleContext, sdkContext android.SdkContext) string {
targetSdkVersionSpec := sdkContext.TargetSdkVersion(ctx)
- if ctx.Config().UnbundledBuildApps() && targetSdkVersionSpec.ApiLevel.IsPreview() {
+ // Return 10000 for modules targeting "current" if either
+ // 1. The module is built in unbundled mode (TARGET_BUILD_APPS not empty)
+ // 2. The module is run as part of MTS, and should be testable on stable branches
+ // TODO(b/240294501): Determine the rules for handling test apexes
+ if targetSdkVersionSpec.ApiLevel.IsPreview() && (ctx.Config().UnbundledBuildApps() || includedInMts(ctx.Module())) {
return strconv.Itoa(android.FutureApiLevel.FinalOrFutureInt())
}
targetSdkVersion, err := targetSdkVersionSpec.EffectiveVersionString(ctx)
@@ -55,6 +59,15 @@
return targetSdkVersion
}
+// Helper function that casts android.Module to java.androidTestApp
+// If this type conversion is possible, it queries whether the test app is included in an MTS suite
+func includedInMts(module android.Module) bool {
+ if test, ok := module.(androidTestApp); ok {
+ return test.includedInTestSuite("mts")
+ }
+ return false
+}
+
type ManifestFixerParams struct {
SdkContext android.SdkContext
ClassLoaderContexts dexpreopt.ClassLoaderContextMap
diff --git a/java/androidmk.go b/java/androidmk.go
index 7322637..a9a21b6 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -618,6 +618,7 @@
if dstubs.apiLintReport != nil {
fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s)\n", dstubs.Name()+"-api-lint",
dstubs.apiLintReport.String(), "apilint/"+dstubs.Name()+"-lint-report.txt")
+ fmt.Fprintf(w, "$(call declare-0p-target,%s)\n", dstubs.apiLintReport.String())
}
}
if dstubs.checkNullabilityWarningsTimestamp != nil {
diff --git a/java/app.go b/java/app.go
index 2a455de..c7fdc0c 100755
--- a/java/app.go
+++ b/java/app.go
@@ -589,16 +589,6 @@
a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
- var noticeAssetPath android.WritablePath
- if Bool(a.appProperties.Embed_notices) || ctx.Config().IsEnvTrue("ALWAYS_EMBED_NOTICES") {
- // The rule to create the notice file can't be generated yet, as the final output path
- // for the apk isn't known yet. Add the path where the notice file will be generated to the
- // aapt rules now before calling aaptBuildActions, the rule to create the notice file will
- // be generated later.
- noticeAssetPath = android.PathForModuleOut(ctx, "NOTICE", "NOTICE.html.gz")
- a.aapt.noticeFile = android.OptionalPathForPath(noticeAssetPath)
- }
-
// Process all building blocks, from AAPT to certificates.
a.aaptBuildActions(ctx)
@@ -673,8 +663,7 @@
a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile)
}
- if a.aapt.noticeFile.Valid() {
- // Generating the notice file rule has to be here after a.outputFile is known.
+ if Bool(a.appProperties.Embed_notices) || ctx.Config().IsEnvTrue("ALWAYS_EMBED_NOTICES") {
noticeFile := android.PathForModuleOut(ctx, "NOTICE.html.gz")
android.BuildNoticeHtmlOutputFromLicenseMetadata(
ctx, noticeFile, "", "",
@@ -683,11 +672,13 @@
android.PathForModuleInstall(ctx).String() + "/",
a.outputFile.String(),
})
+ noticeAssetPath := android.PathForModuleOut(ctx, "NOTICE", "NOTICE.html.gz")
builder := android.NewRuleBuilder(pctx, ctx)
builder.Command().Text("cp").
Input(noticeFile).
Output(noticeAssetPath)
builder.Build("notice_dir", "Building notice dir")
+ a.aapt.noticeFile = android.OptionalPathForPath(noticeAssetPath)
}
for _, split := range a.aapt.splits {
@@ -963,6 +954,18 @@
return true
}
+type androidTestApp interface {
+ includedInTestSuite(searchPrefix string) bool
+}
+
+func (a *AndroidTest) includedInTestSuite(searchPrefix string) bool {
+ return android.PrefixInList(a.testProperties.Test_suites, searchPrefix)
+}
+
+func (a *AndroidTestHelperApp) includedInTestSuite(searchPrefix string) bool {
+ return android.PrefixInList(a.appTestHelperAppProperties.Test_suites, searchPrefix)
+}
+
func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
var configs []tradefed.Config
if a.appTestProperties.Instrumentation_target_package != nil {
diff --git a/java/app_test.go b/java/app_test.go
index 8e331d4..2297ea9 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -3069,3 +3069,65 @@
}
android.AssertStringDoesContain(t, "expected error rule message", fooApk.Args["error"], "missing dependencies: missing_certificate\n")
}
+
+func TestTargetSdkVersionMtsTests(t *testing.T) {
+ platformSdkCodename := "Tiramisu"
+ android_test := "android_test"
+ android_test_helper_app := "android_test_helper_app"
+ bpTemplate := `
+ %v {
+ name: "mytest",
+ target_sdk_version: "%v",
+ test_suites: ["othersuite", "%v"],
+ }
+ `
+ testCases := []struct {
+ desc string
+ moduleType string
+ targetSdkVersionInBp string
+ targetSdkVersionExpected string
+ testSuites string
+ }{
+ {
+ desc: "Non-MTS android_test_apps targeting current should not be upgraded to 10000",
+ moduleType: android_test,
+ targetSdkVersionInBp: "current",
+ targetSdkVersionExpected: platformSdkCodename,
+ testSuites: "non-mts-suite",
+ },
+ {
+ desc: "MTS android_test_apps targeting released sdks should not be upgraded to 10000",
+ moduleType: android_test,
+ targetSdkVersionInBp: "29",
+ targetSdkVersionExpected: "29",
+ testSuites: "mts-suite",
+ },
+ {
+ desc: "MTS android_test_apps targeting current should be upgraded to 10000",
+ moduleType: android_test,
+ targetSdkVersionInBp: "current",
+ targetSdkVersionExpected: "10000",
+ testSuites: "mts-suite",
+ },
+ {
+ desc: "MTS android_test_helper_apps targeting current should be upgraded to 10000",
+ moduleType: android_test_helper_app,
+ targetSdkVersionInBp: "current",
+ targetSdkVersionExpected: "10000",
+ testSuites: "mts-suite",
+ },
+ }
+ fixture := android.GroupFixturePreparers(
+ prepareForJavaTest,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.Platform_sdk_codename = &platformSdkCodename
+ variables.Platform_version_active_codenames = []string{platformSdkCodename}
+ }),
+ )
+ for _, testCase := range testCases {
+ result := fixture.RunTestWithBp(t, fmt.Sprintf(bpTemplate, testCase.moduleType, testCase.targetSdkVersionInBp, testCase.testSuites))
+ mytest := result.ModuleForTests("mytest", "android_common")
+ manifestFixerArgs := mytest.Output("manifest_fixer/AndroidManifest.xml").Args["args"]
+ android.AssertStringDoesContain(t, testCase.desc, manifestFixerArgs, "--targetSdkVersion "+testCase.targetSdkVersionExpected)
+ }
+}
diff --git a/java/dex.go b/java/dex.go
index 84665e7..1638376 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -42,6 +42,9 @@
// True if the module containing this has it set by default.
EnabledByDefault bool `blueprint:"mutated"`
+ // Whether to continue building even if warnings are emitted. Defaults to true.
+ Ignore_warnings *bool
+
// If true, runs R8 in Proguard compatibility mode (default).
// Otherwise, runs R8 in full mode.
Proguard_compatibility *bool
@@ -293,7 +296,10 @@
}
// TODO(b/180878971): missing classes should be added to the relevant builds.
- r8Flags = append(r8Flags, "-ignorewarnings")
+ // TODO(b/229727645): do not use true as default for Android platform builds.
+ if proptools.BoolDefault(opt.Ignore_warnings, true) {
+ r8Flags = append(r8Flags, "-ignorewarnings")
+ }
return r8Flags, r8Deps
}
diff --git a/java/dex_test.go b/java/dex_test.go
index fbdccb6..a3e2ded 100644
--- a/java/dex_test.go
+++ b/java/dex_test.go
@@ -59,6 +59,36 @@
appR8.Args["r8Flags"], libHeader.String())
android.AssertStringDoesNotContain(t, "expected no static_lib header jar in app javac classpath",
appR8.Args["r8Flags"], staticLibHeader.String())
+ android.AssertStringDoesContain(t, "expected -ignorewarnings in app r8 flags",
+ appR8.Args["r8Flags"], "-ignorewarnings")
+}
+
+func TestR8Flags(t *testing.T) {
+ result := PrepareForTestWithJavaDefaultModulesWithoutFakeDex2oatd.RunTestWithBp(t, `
+ android_app {
+ name: "app",
+ srcs: ["foo.java"],
+ platform_apis: true,
+ optimize: {
+ shrink: false,
+ optimize: false,
+ obfuscate: false,
+ ignore_warnings: false,
+ },
+ }
+ `)
+
+ app := result.ModuleForTests("app", "android_common")
+ appR8 := app.Rule("r8")
+ android.AssertStringDoesContain(t, "expected -dontshrink in app r8 flags",
+ appR8.Args["r8Flags"], "-dontshrink")
+ android.AssertStringDoesContain(t, "expected -dontoptimize in app r8 flags",
+ appR8.Args["r8Flags"], "-dontoptimize")
+ android.AssertStringDoesContain(t, "expected -dontobfuscate in app r8 flags",
+ appR8.Args["r8Flags"], "-dontobfuscate")
+ android.AssertStringDoesNotContain(t, "expected no -ignorewarnings in app r8 flags",
+ appR8.Args["r8Flags"], "-ignorewarnings")
+
}
func TestD8(t *testing.T) {
diff --git a/java/platform_bootclasspath_test.go b/java/platform_bootclasspath_test.go
index 1c2a3ae..cb09020 100644
--- a/java/platform_bootclasspath_test.go
+++ b/java/platform_bootclasspath_test.go
@@ -271,7 +271,9 @@
entries := android.AndroidMkEntriesForTest(t, result.TestContext, platformBootclasspath)
goals := entries[0].GetDistForGoals(platformBootclasspath)
android.AssertStringEquals(t, "platform dist goals phony", ".PHONY: droidcore\n", goals[0])
- android.AssertStringEquals(t, "platform dist goals call", "$(call dist-for-goals,droidcore,out/soong/hiddenapi/hiddenapi-flags.csv:hiddenapi-flags.csv)\n", android.StringRelativeToTop(result.Config, goals[1]))
+ android.AssertStringDoesContain(t, "platform dist goals meta check", goals[1], "$(if $(strip $(ALL_TARGETS.")
+ android.AssertStringDoesContain(t, "platform dist goals meta assign", goals[1], "),,$(eval ALL_TARGETS.")
+ android.AssertStringEquals(t, "platform dist goals call", "$(call dist-for-goals,droidcore,out/soong/hiddenapi/hiddenapi-flags.csv:hiddenapi-flags.csv)\n", android.StringRelativeToTop(result.Config, goals[2]))
}
func TestPlatformBootclasspath_HiddenAPIMonolithicFiles(t *testing.T) {