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

Commit c3621424 authored by Pedro Loureiro's avatar Pedro Loureiro Committed by satayev
Browse files

Perform validation of shared library attributes

Perform consistency checks as per http://go/updatable-shared-libraries

These include:
  * no attribute can specified can be less than T
  * max-device-sdk can't be less than min-device-sdk
  * min and max-device-sdk need to be at least the module's
  min_sdk_version
  * using on-bootclasspath-before implies that the module's
  min_sdk_version is at least T or the library has min-device-sdk of at
  least T

Test: m nothing

Bug: 191978330

Change-Id: Iaca5cf23fb0bc7e65effb3529c8e829560894c2e
Merged-In: Iaca5cf23fb0bc7e65effb3529c8e829560894c2e
(cherry picked from commit f9e584dd)
parent 9956e5e2
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -324,7 +324,7 @@ func TestConfig(buildDir string, env map[string]string, bp string, fs map[string
			DeviceName:                        stringPtr("test_device"),
			Platform_sdk_version:              intPtr(30),
			Platform_sdk_codename:             stringPtr("S"),
			Platform_version_active_codenames: []string{"S"},
			Platform_version_active_codenames: []string{"S", "Tiramisu"},
			DeviceSystemSdkVersions:           []string{"14", "15"},
			Platform_systemsdk_versions:       []string{"29", "30"},
			AAPTConfig:                        []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"},
+3 −1
Original line number Diff line number Diff line
@@ -215,7 +215,9 @@ var prepareForApexTest = android.GroupFixturePreparers(
		variables.CertificateOverrides = []string{"myapex_keytest:myapex.certificate.override"}
		variables.Platform_sdk_codename = proptools.StringPtr("Q")
		variables.Platform_sdk_final = proptools.BoolPtr(false)
		variables.Platform_version_active_codenames = []string{"Q"}
		// "Tiramisu" needs to be in the next line for compatibility with soong code,
		// not because of these tests specifically (it's not used by the tests)
		variables.Platform_version_active_codenames = []string{"Q", "Tiramisu"}
		variables.Platform_vndk_version = proptools.StringPtr("29")
	}),
)
+111 −15
Original line number Diff line number Diff line
@@ -1590,6 +1590,11 @@ func (module *SdkLibrary) UniqueApexVariations() bool {

// Creates the xml file that publicizes the runtime library
func (module *SdkLibrary) createXmlFile(mctx android.DefaultableHookContext) {
	moduleMinApiLevel := module.Library.MinSdkVersion(mctx).ApiLevel
	var moduleMinApiLevelStr = moduleMinApiLevel.String()
	if moduleMinApiLevel == android.NoneApiLevel {
		moduleMinApiLevelStr = "current"
	}
	props := struct {
		Name                      *string
		Lib_name                  *string
@@ -1598,6 +1603,7 @@ func (module *SdkLibrary) createXmlFile(mctx android.DefaultableHookContext) {
		On_bootclasspath_before   *string
		Min_device_sdk            *string
		Max_device_sdk            *string
		Sdk_library_min_api_level *string
	}{
		Name:                      proptools.StringPtr(module.xmlPermissionsModuleName()),
		Lib_name:                  proptools.StringPtr(module.BaseModuleName()),
@@ -1606,6 +1612,7 @@ func (module *SdkLibrary) createXmlFile(mctx android.DefaultableHookContext) {
		On_bootclasspath_before:   module.commonSdkLibraryProperties.On_bootclasspath_before,
		Min_device_sdk:            module.commonSdkLibraryProperties.Min_device_sdk,
		Max_device_sdk:            module.commonSdkLibraryProperties.Max_device_sdk,
		Sdk_library_min_api_level: &moduleMinApiLevelStr,
	}

	mctx.CreateModule(sdkLibraryXmlFactory, &props)
@@ -2428,6 +2435,11 @@ type sdkLibraryXmlProperties struct {
	//
	// This means that the device won't recognise this library as installed.
	Max_device_sdk *string

	// The SdkLibrary's min api level as a string
	//
	// This value comes from the ApiLevel of the MinSdkVersion property.
	Sdk_library_min_api_level *string
}

// java_sdk_library_xml builds the permission xml file for a java_sdk_library.
@@ -2535,6 +2547,14 @@ func (module *sdkLibraryXml) permissionsContents(ctx android.ModuleContext) stri
	implicitUntilAttr := formattedOptionalSdkLevelAttribute(ctx, "on_bootclasspath_before", module.properties.On_bootclasspath_before)
	minSdkAttr := formattedOptionalSdkLevelAttribute(ctx, "min_device_sdk", module.properties.Min_device_sdk)
	maxSdkAttr := formattedOptionalSdkLevelAttribute(ctx, "max_device_sdk", module.properties.Max_device_sdk)
	// <library> is understood in all android versions whereas <updatable-library> is only understood from API T (and ignored before that).
	// similarly, min_device_sdk is only understood from T. So if a library is using that, we need to use the updatable-library to make sure this library is not loaded before T
	var libraryTag string
	if module.properties.Min_device_sdk != nil {
		libraryTag = `    <updatable-library\n`
	} else {
		libraryTag = `    <library\n`
	}

	return strings.Join([]string{
		`<?xml version=\"1.0\" encoding=\"utf-8\"?>\n`,
@@ -2553,7 +2573,7 @@ func (module *sdkLibraryXml) permissionsContents(ctx android.ModuleContext) stri
		`    limitations under the License.\n`,
		`-->\n`,
		`<permissions>\n`,
		`    <library\n`,
		libraryTag,
		libNameAttr,
		filePathAttr,
		implicitFromAttr,
@@ -2568,6 +2588,7 @@ func (module *sdkLibraryXml) GenerateAndroidBuildActions(ctx android.ModuleConte
	module.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform()

	libName := proptools.String(module.properties.Lib_name)
	module.selfValidate(ctx)
	xmlContent := module.permissionsContents(ctx)

	module.outputFilePath = android.PathForModuleOut(ctx, libName+".xml").OutputPath
@@ -2601,6 +2622,81 @@ func (module *sdkLibraryXml) AndroidMkEntries() []android.AndroidMkEntries {
	}}
}

func (module *sdkLibraryXml) selfValidate(ctx android.ModuleContext) {
	module.validateAtLeastTAttributes(ctx)
	module.validateMinAndMaxDeviceSdk(ctx)
	module.validateMinMaxDeviceSdkAndModuleMinSdk(ctx)
	module.validateOnBootclasspathBeforeRequirements(ctx)
}

func (module *sdkLibraryXml) validateAtLeastTAttributes(ctx android.ModuleContext) {
	t := android.ApiLevelOrPanic(ctx, "Tiramisu")
	module.attrAtLeastT(ctx, t, module.properties.Min_device_sdk, "min_device_sdk")
	module.attrAtLeastT(ctx, t, module.properties.Max_device_sdk, "max_device_sdk")
	module.attrAtLeastT(ctx, t, module.properties.On_bootclasspath_before, "on_bootclasspath_before")
	module.attrAtLeastT(ctx, t, module.properties.On_bootclasspath_since, "on_bootclasspath_since")
}

func (module *sdkLibraryXml) attrAtLeastT(ctx android.ModuleContext, t android.ApiLevel, attr *string, attrName string) {
	if attr != nil {
		if level, err := android.ApiLevelFromUser(ctx, *attr); err == nil {
			// we will inform the user of invalid inputs when we try to write the
			// permissions xml file so we don't need to do it here
			if t.GreaterThan(level) {
				ctx.PropertyErrorf(attrName, "Attribute value needs to be at least T")
			}
		}
	}
}

func (module *sdkLibraryXml) validateMinAndMaxDeviceSdk(ctx android.ModuleContext) {
	if module.properties.Min_device_sdk != nil && module.properties.Max_device_sdk != nil {
		min, minErr := android.ApiLevelFromUser(ctx, *module.properties.Min_device_sdk)
		max, maxErr := android.ApiLevelFromUser(ctx, *module.properties.Max_device_sdk)
		if minErr == nil && maxErr == nil {
			// we will inform the user of invalid inputs when we try to write the
			// permissions xml file so we don't need to do it here
			if min.GreaterThan(max) {
				ctx.ModuleErrorf("min_device_sdk can't be greater than max_device_sdk")
			}
		}
	}
}

func (module *sdkLibraryXml) validateMinMaxDeviceSdkAndModuleMinSdk(ctx android.ModuleContext) {
	moduleMinApi := android.ApiLevelOrPanic(ctx, *module.properties.Sdk_library_min_api_level)
	if module.properties.Min_device_sdk != nil {
		api, err := android.ApiLevelFromUser(ctx, *module.properties.Min_device_sdk)
		if err == nil {
			if moduleMinApi.GreaterThan(api) {
				ctx.PropertyErrorf("min_device_sdk", "Can't be less than module's min sdk (%s)", moduleMinApi)
			}
		}
	}
	if module.properties.Max_device_sdk != nil {
		api, err := android.ApiLevelFromUser(ctx, *module.properties.Max_device_sdk)
		if err == nil {
			if moduleMinApi.GreaterThan(api) {
				ctx.PropertyErrorf("max_device_sdk", "Can't be less than module's min sdk (%s)", moduleMinApi)
			}
		}
	}
}

func (module *sdkLibraryXml) validateOnBootclasspathBeforeRequirements(ctx android.ModuleContext) {
	moduleMinApi := android.ApiLevelOrPanic(ctx, *module.properties.Sdk_library_min_api_level)
	if module.properties.On_bootclasspath_before != nil {
		t := android.ApiLevelOrPanic(ctx, "Tiramisu")
		// if we use the attribute, then we need to do this validation
		if moduleMinApi.LessThan(t) {
			// if minAPi is < T, then we need to have min_device_sdk (which only accepts T+)
			if module.properties.Min_device_sdk == nil {
				ctx.PropertyErrorf("on_bootclasspath_before", "Using this property requires that the module's min_sdk_version or the shared library's min_device_sdk is at least T")
			}
		}
	}
}

type sdkLibrarySdkMemberType struct {
	android.SdkMemberTypeBase
}
+124 −13
Original line number Diff line number Diff line
@@ -15,12 +15,13 @@
package java

import (
	"android/soong/android"
	"fmt"
	"path/filepath"
	"regexp"
	"testing"

	"android/soong/android"

	"github.com/google/blueprint/proptools"
)

@@ -171,16 +172,20 @@ func TestJavaSdkLibrary_UpdatableLibrary(t *testing.T) {
			"29": {"foo"},
			"30": {"foo", "fooUpdatable", "fooUpdatableErr"},
		}),
		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
			variables.Platform_version_active_codenames = []string{"Tiramisu", "U", "V", "W"}
		}),
	).RunTestWithBp(t,
		`
		java_sdk_library {
			name: "fooUpdatable",
			srcs: ["a.java", "b.java"],
			api_packages: ["foo"],
		  on_bootclasspath_since: "29",
		  on_bootclasspath_before: "30",
		  min_device_sdk: "R",
			on_bootclasspath_since: "U",
			on_bootclasspath_before: "V",
			min_device_sdk: "W",
			max_device_sdk: "current",
			min_sdk_version: "S",
		}
		java_sdk_library {
			name: "foo",
@@ -190,9 +195,9 @@ func TestJavaSdkLibrary_UpdatableLibrary(t *testing.T) {
`)
	// test that updatability attributes are passed on correctly
	fooUpdatable := result.ModuleForTests("fooUpdatable.xml", "android_common").Rule("java_sdk_xml")
	android.AssertStringDoesContain(t, "fooUpdatable.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `on_bootclasspath_since=\"29\"`)
	android.AssertStringDoesContain(t, "fooUpdatable.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `on_bootclasspath_before=\"30\"`)
	android.AssertStringDoesContain(t, "fooUpdatable.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `min_device_sdk=\"30\"`)
	android.AssertStringDoesContain(t, "fooUpdatable.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `on_bootclasspath_since=\"9001\"`)
	android.AssertStringDoesContain(t, "fooUpdatable.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `on_bootclasspath_before=\"9002\"`)
	android.AssertStringDoesContain(t, "fooUpdatable.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `min_device_sdk=\"9003\"`)
	android.AssertStringDoesContain(t, "fooUpdatable.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `max_device_sdk=\"10000\"`)

	// double check that updatability attributes are not written if they don't exist in the bp file
@@ -204,7 +209,7 @@ func TestJavaSdkLibrary_UpdatableLibrary(t *testing.T) {
	android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooPermissions.RuleParams.Command, `max_device_sdk`)
}

func TestJavaSdkLibrary_UpdatableLibrary_Validation(t *testing.T) {
func TestJavaSdkLibrary_UpdatableLibrary_Validation_ValidVersion(t *testing.T) {
	android.GroupFixturePreparers(
		prepareForJavaTest,
		PrepareForTestWithJavaSdkLibraryFiles,
@@ -231,6 +236,112 @@ func TestJavaSdkLibrary_UpdatableLibrary_Validation(t *testing.T) {
`)
}

func TestJavaSdkLibrary_UpdatableLibrary_Validation_AtLeastTAttributes(t *testing.T) {
	android.GroupFixturePreparers(
		prepareForJavaTest,
		PrepareForTestWithJavaSdkLibraryFiles,
		FixtureWithPrebuiltApis(map[string][]string{
			"28": {"foo"},
		}),
	).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(
		[]string{
			"on_bootclasspath_since: Attribute value needs to be at least T",
			"on_bootclasspath_before: Attribute value needs to be at least T",
			"min_device_sdk: Attribute value needs to be at least T",
			"max_device_sdk: Attribute value needs to be at least T",
		},
	)).RunTestWithBp(t,
		`
		java_sdk_library {
			name: "foo",
			srcs: ["a.java", "b.java"],
			api_packages: ["foo"],
			on_bootclasspath_since: "S",
			on_bootclasspath_before: "S",
			min_device_sdk: "S",
			max_device_sdk: "S",
			min_sdk_version: "S",
		}
`)
}

func TestJavaSdkLibrary_UpdatableLibrary_Validation_MinAndMaxDeviceSdk(t *testing.T) {
	android.GroupFixturePreparers(
		prepareForJavaTest,
		PrepareForTestWithJavaSdkLibraryFiles,
		FixtureWithPrebuiltApis(map[string][]string{
			"28": {"foo"},
		}),
		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
			variables.Platform_version_active_codenames = []string{"Tiramisu", "U", "V"}
		}),
	).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(
		[]string{
			"min_device_sdk can't be greater than max_device_sdk",
		},
	)).RunTestWithBp(t,
		`
		java_sdk_library {
			name: "foo",
			srcs: ["a.java", "b.java"],
			api_packages: ["foo"],
			min_device_sdk: "V",
			max_device_sdk: "U",
			min_sdk_version: "S",
		}
`)
}

func TestJavaSdkLibrary_UpdatableLibrary_Validation_MinAndMaxDeviceSdkAndModuleMinSdk(t *testing.T) {
	android.GroupFixturePreparers(
		prepareForJavaTest,
		PrepareForTestWithJavaSdkLibraryFiles,
		FixtureWithPrebuiltApis(map[string][]string{
			"28": {"foo"},
		}),
		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
			variables.Platform_version_active_codenames = []string{"Tiramisu", "U", "V"}
		}),
	).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(
		[]string{
			regexp.QuoteMeta("min_device_sdk: Can't be less than module's min sdk (V)"),
			regexp.QuoteMeta("max_device_sdk: Can't be less than module's min sdk (V)"),
		},
	)).RunTestWithBp(t,
		`
		java_sdk_library {
			name: "foo",
			srcs: ["a.java", "b.java"],
			api_packages: ["foo"],
			min_device_sdk: "U",
			max_device_sdk: "U",
			min_sdk_version: "V",
		}
`)
}

func TestJavaSdkLibrary_UpdatableLibrary_usesNewTag(t *testing.T) {
	result := android.GroupFixturePreparers(
		prepareForJavaTest,
		PrepareForTestWithJavaSdkLibraryFiles,
		FixtureWithPrebuiltApis(map[string][]string{
			"30": {"foo"},
		}),
	).RunTestWithBp(t,
		`
		java_sdk_library {
			name: "foo",
			srcs: ["a.java", "b.java"],
			min_device_sdk: "Tiramisu",
			min_sdk_version: "S",
		}
`)
	// test that updatability attributes are passed on correctly
	fooUpdatable := result.ModuleForTests("foo.xml", "android_common").Rule("java_sdk_xml")
	android.AssertStringDoesContain(t, "foo.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `<updatable-library`)
	android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `<library`)
}

func TestJavaSdkLibrary_StubOrImplOnlyLibs(t *testing.T) {
	result := android.GroupFixturePreparers(
		prepareForJavaTest,