Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bc98b415 authored by Jihoon Kang's avatar Jihoon Kang Committed by Gerrit Code Review
Browse files

Merge changes from topic "stub_validation" into main

* changes:
  Add current api check as validation for from-text stub generation
  Disable full_api_surface_stubs for some java_api_library modules
parents aea8ba35 063ec003
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -66,6 +66,7 @@ java_api_library {
    libs: [
        "stub-annotations",
    ],
    enable_validation: false,
}

java_library {
+9 −0
Original line number Diff line number Diff line
@@ -171,6 +171,10 @@ type ApiStubsProvider interface {
	ApiStubsSrcProvider
}

type currentApiTimestampProvider interface {
	CurrentApiTimestamp() android.Path
}

// droidstubs passes sources files through Metalava to generate stub .java files that only contain the API to be
// documented, filtering out hidden classes and methods.  The resulting .java files are intended to be passed to
// a droiddoc module to generate documentation.
@@ -238,10 +242,15 @@ func (d *Droidstubs) StubsSrcJar() android.Path {
	return d.stubsSrcJar
}

func (d *Droidstubs) CurrentApiTimestamp() android.Path {
	return d.checkCurrentApiTimestamp
}

var metalavaMergeAnnotationsDirTag = dependencyTag{name: "metalava-merge-annotations-dir"}
var metalavaMergeInclusionAnnotationsDirTag = dependencyTag{name: "metalava-merge-inclusion-annotations-dir"}
var metalavaAPILevelsAnnotationsDirTag = dependencyTag{name: "metalava-api-levels-annotations-dir"}
var metalavaAPILevelsModuleTag = dependencyTag{name: "metalava-api-levels-module-tag"}
var metalavaCurrentApiTimestampTag = dependencyTag{name: "metalava-current-api-timestamp-tag"}

func (d *Droidstubs) DepsMutator(ctx android.BottomUpMutatorContext) {
	d.Javadoc.addDeps(ctx)
+1 −1
Original line number Diff line number Diff line
@@ -392,7 +392,7 @@ func TestGeneratedApiContributionVisibilityTest(t *testing.T) {
						removed_api_file: "A/removed.txt",
					}
				},
				visibility: ["//a"],
				visibility: ["//a", "//b"],
			}
		`,
		map[string][]byte{
+41 −2
Original line number Diff line number Diff line
@@ -1664,6 +1664,8 @@ type ApiLibrary struct {
	extractedSrcJar           android.WritablePath
	// .dex of stubs, used for hiddenapi processing
	dexJarFile OptionalDexJarPath

	validationPaths android.Paths
}

type JavaApiLibraryProperties struct {
@@ -1699,6 +1701,12 @@ type JavaApiLibraryProperties struct {
	// The jar will also be passed to metalava as a classpath to
	// generate compilable stubs.
	System_modules *string

	// If true, the module runs validation on the API signature files provided
	// by the modules passed via api_contributions by checking if the files are
	// in sync with the source Java files. However, the environment variable
	// DISABLE_STUB_VALIDATION has precedence over this property.
	Enable_validation *bool
}

func ApiLibraryFactory() android.Module {
@@ -1787,6 +1795,12 @@ func (al *ApiLibrary) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBui
	}
}

func (al *ApiLibrary) addValidation(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, validationPaths android.Paths) {
	for _, validationPath := range validationPaths {
		cmd.Validation(validationPath)
	}
}

// This method extracts the stub class files from the stub jar file provided
// from full_api_surface_stub module instead of compiling the srcjar generated from invoking metalava.
// This method is used because metalava can generate compilable from-text stubs only when
@@ -1823,8 +1837,28 @@ func (al *ApiLibrary) extractApiSrcs(ctx android.ModuleContext, rule *android.Ru

func (al *ApiLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
	apiContributions := al.properties.Api_contributions
	addValidations := !ctx.Config().IsEnvTrue("DISABLE_STUB_VALIDATION") &&
		proptools.BoolDefault(al.properties.Enable_validation, true)
	for _, apiContributionName := range apiContributions {
		ctx.AddDependency(ctx.Module(), javaApiContributionTag, apiContributionName)

		// Add the java_api_contribution module generating droidstubs module
		// as dependency when validation adding conditions are met and
		// the java_api_contribution module name has ".api.contribution" suffix.
		// All droidstubs-generated modules possess the suffix in the name,
		// but there is no such guarantee for tests.
		if addValidations {
			if strings.HasSuffix(apiContributionName, ".api.contribution") {
				ctx.AddDependency(ctx.Module(), metalavaCurrentApiTimestampTag, strings.TrimSuffix(apiContributionName, ".api.contribution"))
			} else {
				ctx.ModuleErrorf("Validation is enabled for module %s but a "+
					"current timestamp provider is not found for the api "+
					"contribution %s",
					ctx.ModuleName(),
					apiContributionName,
				)
			}
		}
	}
	ctx.AddVariationDependencies(nil, libTag, al.properties.Libs...)
	ctx.AddVariationDependencies(nil, staticLibTag, al.properties.Static_libs...)
@@ -1862,8 +1896,7 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
		android.PathForModuleOut(ctx, "metalava.sbox.textproto")).
		SandboxInputs()

	var stubsDir android.OptionalPath
	stubsDir = android.OptionalPathForPath(android.PathForModuleOut(ctx, "metalava", "stubsDir"))
	stubsDir := android.OptionalPathForPath(android.PathForModuleOut(ctx, "metalava", "stubsDir"))
	rule.Command().Text("rm -rf").Text(stubsDir.String())
	rule.Command().Text("mkdir -p").Text(stubsDir.String())

@@ -1895,6 +1928,10 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
		case systemModulesTag:
			module := dep.(SystemModulesProvider)
			systemModulesPaths = append(systemModulesPaths, module.HeaderJars()...)
		case metalavaCurrentApiTimestampTag:
			if currentApiTimestampProvider, ok := dep.(currentApiTimestampProvider); ok {
				al.validationPaths = append(al.validationPaths, currentApiTimestampProvider.CurrentApiTimestamp())
			}
		}
	})

@@ -1918,6 +1955,8 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
		cmd.FlagWithInput("--migrate-nullness ", previousApi)
	}

	al.addValidation(ctx, cmd, al.validationPaths)

	al.stubsSrcJar = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-"+"stubs.srcjar")
	al.stubsJarWithoutStaticLibs = android.PathForModuleOut(ctx, "metalava", "stubs.jar")
	al.stubsJar = android.PathForModuleOut(ctx, ctx.ModuleName(), fmt.Sprintf("%s.jar", ctx.ModuleName()))
+166 −50
Original line number Diff line number Diff line
@@ -1847,9 +1847,17 @@ func TestDeviceBinaryWrapperGeneration(t *testing.T) {
}

func TestJavaApiContributionEmptyApiFile(t *testing.T) {
	testJavaError(t,
	android.GroupFixturePreparers(
		prepareForJavaTest,
		android.FixtureMergeEnv(
			map[string]string{
				"DISABLE_STUB_VALIDATION": "true",
			},
		),
	).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
		"Error: foo has an empty api file.",
		`java_api_contribution {
	)).RunTestWithBp(t, `
		java_api_contribution {
			name: "foo",
		}
		java_api_library {
@@ -1874,7 +1882,20 @@ func TestJavaApiLibraryAndProviderLink(t *testing.T) {
		api_surface: "public",
	}
	`
	ctx, _ := testJavaWithFS(t, `
	ctx := android.GroupFixturePreparers(
		prepareForJavaTest,
		android.FixtureMergeMockFs(
			map[string][]byte{
				"a/Android.bp": []byte(provider_bp_a),
				"b/Android.bp": []byte(provider_bp_b),
			},
		),
		android.FixtureMergeEnv(
			map[string]string{
				"DISABLE_STUB_VALIDATION": "true",
			},
		),
	).RunTestWithBp(t, `
		java_api_library {
			name: "bar1",
			api_surface: "public",
@@ -1886,11 +1907,7 @@ func TestJavaApiLibraryAndProviderLink(t *testing.T) {
			api_surface: "system",
			api_contributions: ["foo1", "foo2"],
		}
		`,
		map[string][]byte{
			"a/Android.bp": []byte(provider_bp_a),
			"b/Android.bp": []byte(provider_bp_b),
		})
	`)

	testcases := []struct {
		moduleName         string
@@ -1944,7 +1961,22 @@ func TestJavaApiLibraryAndDefaultsLink(t *testing.T) {
		api_surface: "system",
	}
	`
	ctx, _ := testJavaWithFS(t, `
	ctx := android.GroupFixturePreparers(
		prepareForJavaTest,
		android.FixtureMergeMockFs(
			map[string][]byte{
				"a/Android.bp": []byte(provider_bp_a),
				"b/Android.bp": []byte(provider_bp_b),
				"c/Android.bp": []byte(provider_bp_c),
				"d/Android.bp": []byte(provider_bp_d),
			},
		),
		android.FixtureMergeEnv(
			map[string]string{
				"DISABLE_STUB_VALIDATION": "true",
			},
		),
	).RunTestWithBp(t, `
		java_defaults {
			name: "baz1",
			api_surface: "public",
@@ -1975,13 +2007,7 @@ func TestJavaApiLibraryAndDefaultsLink(t *testing.T) {
			defaults:["baz1", "baz2"],
			api_contributions: ["foo4"],
		}
		`,
		map[string][]byte{
			"a/Android.bp": []byte(provider_bp_a),
			"b/Android.bp": []byte(provider_bp_b),
			"c/Android.bp": []byte(provider_bp_c),
			"d/Android.bp": []byte(provider_bp_d),
		})
	`)

	testcases := []struct {
		moduleName         string
@@ -2026,7 +2052,20 @@ func TestJavaApiLibraryJarGeneration(t *testing.T) {
		api_surface: "public",
	}
	`
	ctx, _ := testJavaWithFS(t, `
	ctx := android.GroupFixturePreparers(
		prepareForJavaTest,
		android.FixtureMergeMockFs(
			map[string][]byte{
				"a/Android.bp": []byte(provider_bp_a),
				"b/Android.bp": []byte(provider_bp_b),
			},
		),
		android.FixtureMergeEnv(
			map[string]string{
				"DISABLE_STUB_VALIDATION": "true",
			},
		),
	).RunTestWithBp(t, `
		java_api_library {
			name: "bar1",
			api_surface: "public",
@@ -2038,11 +2077,7 @@ func TestJavaApiLibraryJarGeneration(t *testing.T) {
			api_surface: "system",
			api_contributions: ["foo1", "foo2"],
		}
		`,
		map[string][]byte{
			"a/Android.bp": []byte(provider_bp_a),
			"b/Android.bp": []byte(provider_bp_b),
		})
	`)

	testcases := []struct {
		moduleName    string
@@ -2094,7 +2129,24 @@ func TestJavaApiLibraryLibsLink(t *testing.T) {
	}
	`

	ctx, _ := testJavaWithFS(t, `
	ctx := android.GroupFixturePreparers(
		prepareForJavaTest,
		android.FixtureMergeMockFs(
			map[string][]byte{
				"a/Android.bp": []byte(provider_bp_a),
				"b/Android.bp": []byte(provider_bp_b),
				"c/Android.bp": []byte(lib_bp_a),
				"c/Lib.java":   {},
				"d/Android.bp": []byte(lib_bp_b),
				"d/Lib.java":   {},
			},
		),
		android.FixtureMergeEnv(
			map[string]string{
				"DISABLE_STUB_VALIDATION": "true",
			},
		),
	).RunTestWithBp(t, `
		java_api_library {
			name: "bar1",
			api_surface: "public",
@@ -2108,15 +2160,7 @@ func TestJavaApiLibraryLibsLink(t *testing.T) {
			api_contributions: ["foo1", "foo2"],
			libs: ["lib1", "lib2", "bar1"],
		}
		`,
		map[string][]byte{
			"a/Android.bp": []byte(provider_bp_a),
			"b/Android.bp": []byte(provider_bp_b),
			"c/Android.bp": []byte(lib_bp_a),
			"c/Lib.java":   {},
			"d/Android.bp": []byte(lib_bp_b),
			"d/Lib.java":   {},
		})
	`)

	testcases := []struct {
		moduleName        string
@@ -2171,7 +2215,24 @@ func TestJavaApiLibraryStaticLibsLink(t *testing.T) {
	}
	`

	ctx, _ := testJavaWithFS(t, `
	ctx := android.GroupFixturePreparers(
		prepareForJavaTest,
		android.FixtureMergeMockFs(
			map[string][]byte{
				"a/Android.bp": []byte(provider_bp_a),
				"b/Android.bp": []byte(provider_bp_b),
				"c/Android.bp": []byte(lib_bp_a),
				"c/Lib.java":   {},
				"d/Android.bp": []byte(lib_bp_b),
				"d/Lib.java":   {},
			},
		),
		android.FixtureMergeEnv(
			map[string]string{
				"DISABLE_STUB_VALIDATION": "true",
			},
		),
	).RunTestWithBp(t, `
		java_api_library {
			name: "bar1",
			api_surface: "public",
@@ -2185,15 +2246,7 @@ func TestJavaApiLibraryStaticLibsLink(t *testing.T) {
			api_contributions: ["foo1", "foo2"],
			static_libs: ["lib1", "lib2", "bar1"],
		}
		`,
		map[string][]byte{
			"a/Android.bp": []byte(provider_bp_a),
			"b/Android.bp": []byte(provider_bp_b),
			"c/Android.bp": []byte(lib_bp_a),
			"c/Lib.java":   {},
			"d/Android.bp": []byte(lib_bp_b),
			"d/Lib.java":   {},
		})
	`)

	testcases := []struct {
		moduleName        string
@@ -2242,19 +2295,28 @@ func TestJavaApiLibraryFullApiSurfaceStub(t *testing.T) {
	}
	`

	ctx, _ := testJavaWithFS(t, `
	ctx := android.GroupFixturePreparers(
		prepareForJavaTest,
		android.FixtureMergeMockFs(
			map[string][]byte{
				"a/Android.bp": []byte(provider_bp_a),
				"b/Android.bp": []byte(provider_bp_b),
				"c/Android.bp": []byte(lib_bp_a),
			},
		),
		android.FixtureMergeEnv(
			map[string]string{
				"DISABLE_STUB_VALIDATION": "true",
			},
		),
	).RunTestWithBp(t, `
		java_api_library {
			name: "bar1",
			api_surface: "public",
			api_contributions: ["foo1"],
			full_api_surface_stub: "lib1",
		}
		`,
		map[string][]byte{
			"a/Android.bp": []byte(provider_bp_a),
			"b/Android.bp": []byte(provider_bp_b),
			"c/Android.bp": []byte(lib_bp_a),
		})
	`)

	m := ctx.ModuleForTests("bar1", "android_common")
	manifest := m.Output("metalava.sbox.textproto")
@@ -2402,7 +2464,14 @@ func TestHeadersOnly(t *testing.T) {
}

func TestJavaApiContributionImport(t *testing.T) {
	ctx, _ := testJava(t, `
	ctx := android.GroupFixturePreparers(
		prepareForJavaTest,
		android.FixtureMergeEnv(
			map[string]string{
				"DISABLE_STUB_VALIDATION": "true",
			},
		),
	).RunTestWithBp(t, `
		java_api_library {
			name: "foo",
			api_contributions: ["bar"],
@@ -2483,3 +2552,50 @@ func TestSdkLibraryProvidesSystemModulesToApiLibrary(t *testing.T) {
	classPathFlag := "--classpath __SBOX_SANDBOX_DIR__/out/.intermediates/bar/android_common/turbine-combined/bar.jar"
	android.AssertStringDoesContain(t, "command expected to contain classpath flag", manifestCommand, classPathFlag)
}

func TestApiLibraryDroidstubsDependency(t *testing.T) {
	result := android.GroupFixturePreparers(
		prepareForJavaTest,
		PrepareForTestWithJavaSdkLibraryFiles,
		FixtureWithLastReleaseApis("foo"),
		android.FixtureModifyConfig(func(config android.Config) {
			config.SetApiLibraries([]string{"foo"})
		}),
		android.FixtureMergeMockFs(
			map[string][]byte{
				"A.java": nil,
			},
		),
	).RunTestWithBp(t, `
		java_api_library {
			name: "foo",
			api_contributions: [
				"api-stubs-docs-non-updatable.api.contribution",
			],
			enable_validation: true,
		}
		java_api_library {
			name: "bar",
			api_contributions: [
				"api-stubs-docs-non-updatable.api.contribution",
			],
			enable_validation: false,
		}
	`)

	currentApiTimestampPath := "api-stubs-docs-non-updatable/android_common/metalava/check_current_api.timestamp"
	foo := result.ModuleForTests("foo", "android_common").Module().(*ApiLibrary)
	fooValidationPathsString := strings.Join(foo.validationPaths.Strings(), " ")
	bar := result.ModuleForTests("bar", "android_common").Module().(*ApiLibrary)
	barValidationPathsString := strings.Join(bar.validationPaths.Strings(), " ")
	android.AssertStringDoesContain(t,
		"Module expected to have validation",
		fooValidationPathsString,
		currentApiTimestampPath,
	)
	android.AssertStringDoesNotContain(t,
		"Module expected to not have validation",
		barValidationPathsString,
		currentApiTimestampPath,
	)
}
Loading